【问题标题】:Nested loops in RubyRuby 中的嵌套循环
【发布时间】:2015-11-22 06:13:48
【问题描述】:

我正在尝试计算 Ruby 中字符串的相似前缀开头的数量。例如;输入“ababaa”应该输出11;

ababaa = 6
 babaa = 0
  abaa = 3
   baa = 0
    aa = 1
     a = 1

我已经了解了下面的代码,使用嵌套循环将上述每个作为数组进行遍历,但是看起来 Ruby 当前仅输出第一个 Array 对象“ababaa”的计数。

已解决,谢谢:)

def string_suffix(string)
num = 0
ary = []
string.length.times do
  ary << string[num..string.length]
  num = num + 1
end
result = 0
ary.each do |x| # ["ababaa", "babaa", "abaa", "baa", "aa", "a"] 
  x.chars.each_with_index do |c,index|
    break unless c == string[index]
      result = result + 1
  end
end
return result
end

我已经看得很远了,但仍然无法解决这个问题,看起来(最终的,嵌套的)数组在“ary”数组的第一次迭代后中断了,只是返回了那个输出。

【问题讨论】:

  • 您是否打算在这里分配作业:if x = string[count]?因为= 是赋值,所以不检查是否相等。因此,if 表达式将是 true 任何时候 string[count] 的值为真值,即任何时候它都非零。
  • 不,我没有看到,谢谢。结果还是一样,带回来6
  • 每次通过ary.each 循环时,您也会将result 归零。将result = 0 放在 ary.each... 之前。 num 在第一个循环之后似乎没有用于任何事情,因此不需要 num = 0
  • 是的,谢谢,我也看到了。当然输出还是6。
  • 除了最后一次迭代的结果,你不会输出任何东西。如果您想为数组中的每个项目输出结果,那么(a)在循环中输出它,或者(b)收集结果并在迭代完成后输出它们。

标签: arrays ruby iteration suffix-array


【解决方案1】:

据我了解,问题是这样的:给定一个字符串s,对于每个i = 0..s.size-1,计算s[0..-i-1] 与@987654326 的相应字符(即相同偏移量)匹配的前导字符数@,并将这些 s.size 小计相加。

这是一种类似于 Ruby 的方式,使用 Enumerable#reduce(又名 inject)和 Enumerable#take_while

str = "ababaa"

arr = str.chars
(0...arr.size).reduce(0) do |tot,i|
  tot + arr[0..-i-1].zip(arr[i..-1]).take_while { |x,y| x == y }.size
end
  #=> 11

步骤:

arr = str.chars
  #=> ["a", "b", "a", "b", "a", "a"] 
r = 0...arr.size
  #=> 0...6 

r的第一个元素传递给块时,块变量设置为:

tot = 0
i   = 0

因此块计算如下:

a = arr[0..-i-1].zip(arr[i..-1])
  #=> arr[0..-1].zip(arr[0..-1])
  #=> arr.zip(arr)
  #=> ["a", "b", "a", "b", "a", "a"].zip(["a", "b", "a", "b", "a", "a"])
  #=> [["a", "a"], ["b", "b"], ["a", "a"], ["b", "b"], ["a", "a"], ["a", "a"]]

b = a.take_while { |x,y| x == y }
  #=> [["a", "a"], ["b", "b"], ["a", "a"], ["b", "b"], ["a", "a"], ["a", "a"]]

tot + b.size
  #=> 0 + 6
  #=> 6

请注意,对于传递给块的arr 的第一个元素,此计算将始终等于arr.size

arr 的下一个元素被传递给块时,块变量i 被设置为1。我们刚刚计算的tot 等于6。因此,块计算为:

a = arr[0..-i-1].zip(arr[i..-1])
  #=> arr[0..-2].zip(arr[1..-1])
  #=> ["a", "b", "a", "b", "a"].zip(["b", "a", "b", "a", "a"])
  #=> [["a", "b"], ["b", "a"], ["a", "b"], ["b", "a"], ["a", "a"]] 

b = a.take_while { |x,y| x == y }
  #=> [] 
tot + b.size
  #=> 6 + 0
  #=> 6

其余的计算类似。在arr 的所有元素都发送到块后,reduce 返回tot 的值。

【讨论】:

    【解决方案2】:

    当您仍在循环中时,您正在返回结果。您需要将result = 0 移出循环,并将return result 语句也移出循环。目前该函数正在执行循环的第一次迭代(“ababaa”,所有字符都匹配),但您希望结果等于所有结果的总和。

    另外,不要这样做:

    count = 0
    x.chars.each do |x|
        if x == string[count]
            count = count + 1
            result = result + 1
        else
            count = count + 1
        end
    end
    

    你可以使用 each_with_index 函数来获取

    x.chars.each_with_index do |c,index|
        if c == string[index]
            result = result + 1
        end
    end
    

    但是,由于您要计算子字符串中有多少个字符是字符串的前缀,因此您希望在第一次找到不等于 string[index] 的字符 c 时中断,这样您就不会最终计算额外的字符。然后循环变为:

    x.chars.each_with_index do |c,index|
        if c == string[index]
            result = result + 1
        else
            break
        end
    end
    

    【讨论】:

    • 太棒了,谢谢,尽管在我的程序中出于某种原因,您的第二个建议返回 13。
    • 查看我编辑的评论,了解我使用的更改。
    • 那是因为您使用的逻辑略有错误,正如 lurker 对您问题的评论所解释的那样。如果 c != string[index] 则需要中断,因为这样我们就知道 x 不再是字符串的前缀。我会把它添加到我的答案中。
    • 啊!是的,当然,循环将继续迭代,除非它被破坏。再次感谢:)
    【解决方案3】:

    我注意到您在最后的第二个循环中返回了结果。这意味着在您完成数组中的第一项之后,该函数仅返回第一项的结果。将你的 return 语句移到循环之外。

    【讨论】:

      猜你喜欢
      • 2013-06-10
      • 1970-01-01
      • 2016-10-19
      • 1970-01-01
      • 1970-01-01
      • 2015-08-25
      • 1970-01-01
      • 1970-01-01
      • 2021-03-13
      相关资源
      最近更新 更多