2017-04-14 105 views
3

我想实现一个函数,该函数从传递给它的变量中返回第一个非空字符串。不幸的是,一些变量可能是零,所以很自然的做法如何创建一个返回传递给它的第一个非零,非空字符串的函数?

function first_non_empty(...) 
    for i, item in ipairs({...}) do 
     if item ~= nil and item ~= '' then 
      return item 
     end 
    end 
    return '' 
end 

不起作用:ipairs尽快退出了,因为它遇到一个零值。这可以通过改变需求来修改,以便变量不能为零,或者通过将长度传递给函数,因此表长度不必依赖于ipairs,或者通过将所有参数封装在函数中,他们明确没有

function first_non_empty_func(...) 
    for i, func in ipairs({...}) do 
     local item = func() 
     if item ~= nil and item ~= '' then 
      return item 
     end 
    end 
    return '' 
end 

function fn(p) 
    local f = function() return p end 
    return f 
end 

-- change callers to first_non_empty_func(fn(a), fn(b), fn(c)) 

但是,这些解决方案都使函数原型复杂化。是否存在一个采用有序参数列表的函数,其中一些参数可能为零,它将返回非零的非零参数和不为空字符串的第一个参数?

回答

3

select('#', ...)可以用来获取提供的参数个数,所以这里不使用table.pack一种替代方案:

function first_non_empty_pack(...) 
    for i = 1, select('#', ...) do 
     local item = select(i, ...) 
     if item ~= nil and item ~= '' then 
      return item 
     end 
    end 
    return '' 
end 
+0

不错!作为奖励,因为'select'在5.1中出现,而'table.pack'不在,我可以在Scribunto中使用它。 –

+0

@ChrisMidgley'函数table.pack(...)return {n = select('#',...),...} end'就是全部。对于long vararg列表,重复复制'select'调用的列表可能比创建一次表并慢慢迭代要慢。另一方面,创建需要稍后垃圾回收的表可能会变慢。所以基准测试可以看出哪一个在你的案例中更快(或者只是选择你认为更清洁的一个,直到你看到速度实际上是一个问题)。 – nobody

4

使用table.pack,它保留了所有零条目,并返回在n领域的条目数:

function first_non_empty_pack(...) 
    local t = table.pack(...) 
    for i = 1, t.n do 
     local item = t[i] 
     if item ~= nil and item ~= '' then 
      return item 
     end 
    end 
    return '' 
end 
1

简单的方法是使用递归。没有创建额外的表格等:

function first_non_empty(item, ...) 
    if item ~= nil and item ~= '' then return item end 
    return first_non_empty(...) 
end 

但是列表必须以一些结束标记结束。例如,boolean'false',表示没有非零非空字符串。

+0

不需要结束标志,'选择(“#”,.. 。)== 0'可以用作停止条件。避免重复的“select”调用的另一种方法是首先确定计数,然后如'item local = rec(n,item,...)那样倒计数,如果item〜= nil和item〜=''则返回item elseif n> 0,然后返回rec(n-1,...)end end function first_non_empty(...)return rec(select('#',...),...)end end'。 – nobody

+0

结束标记使得这个函数更快,更简单。另外,结束标记可以不是布尔值,而是一些后备字符串值,当没有找到其他字符串时应该返回。这可以节省一些此功能之外的检查。这一切都取决于实际需要,而这个功能只是其中的一种:) – Vlad

相关问题