如果我的代码关闭,请原谅我。我仍然掌握在Ruby on Rails中,这似乎有微妙的差异,因为我学到更多“只是Ruby”,尽管公平地说我不确定我的代码是否会以Ruby on Rails格式通过。我离题了。
我试图比较两个包含一组字符串的数组。我想做几件事。 1)确保数组的单词数相同,否则练习没有实际意义。 2)比较数组中的第一个字与仅第二个数组中的第一个字。换句话说,我从不想比较数组“a”中的单词1和数组“b”中的单词4。我正在努力找到一个解决方案,重新排序任何给定单词中的字符,将其与第二个数组中相应单词中的重新排序字符进行比较,如果它是一个字谜,则打印1(一旦排序,这个想法就是两个单词如果它们不相符,则为0或0;
在下面的示例中,我想要打印的内容是:
0
0
1
1
......但事实并非如此。思考?我担心这与局部变量问题有关,但我不确定。
a = ['hello', 'goodbye', 'pants', 'baa']
b = ['helio', 'godbye', 'spant', 'aba']
x = a.length
y = b.length
z = 0
x = y? do
while z < x do
if a.find(z).chars.sort.join == b.find(z).chars.sort.join
puts 1
else
puts 0
end
z += 1
end
end
答案 0 :(得分:3)
这不一定是火箭科学。事实上,只要你能够始终如一地代表每个阵列,它就是一个明智的选择:
a = ['hello', 'goodbye', 'pants', 'baa']
b = ['helio', 'godbye', 'spant', 'aba']
c = ['lohel', 'goedboy', 'spant', 'aab']
def anagram_flatten(array)
array.collect do |word|
word.chars.sort.join
end
end
puts anagram_flatten(a) == anagram_flatten(b)
# => false
puts anagram_flatten(a) == anagram_flatten(c)
# => true
当一个简单的数组与阵列比较无论如何都非常快时,我不担心部分比较。
答案 1 :(得分:3)
[编辑:我编辑了我的答案,将@raph建议的效率改进纳入了对该问题的评论(下面的方法anagram?
)。这可能没有必要,但我认为这是一个好主意,它应该得到一些曝光。我也给出了一个详细的解释,因为OP是Ruby的新手,也可能是其他读者。]
您可以考虑按以下方式执行此操作。
<强> 代码 强>
def anagrams(a, b)
return nil unless a.size == b.size
a.zip(b).map { |aw,bw| anagram?(aw,bw) ? 1 : 0 }
end
def anagram?(aw, bw)
return false unless aw.size == bw.size
counts = aw.downcase.each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 }
bw.downcase.each_char do |c|
return false unless counts[c] > 0
counts[c] -= 1
end
true
end
<强> 实施例 强>
a = ['hello', 'goodbye', 'pants', 'baa']
b = ['helio', 'godbye', 'Spant', 'aba']
anagrams(a, b)
#=> [0, 0, 1, 1]
<强> 解释 强>
anagrams
方法
对于上面的例子,
a.size #=> 4
b.size #=> 4
所以我们不会在nil
的第一行返回anagrams
。
接下来,
c = a.zip(b)
#=> [["hello", "helio"], ["goodbye", "godbye"],
# ["pants", "Spant"], ["baa", "aba"]]
假设anagram?
暂时按预期工作:
c.map { |e| anagram?(e.first, e.last) ? 1 : 0 }
#=> [0, 0, 1, 1]
Enumerable#map将c
(一个双元素数组)的每个元素传递给块。 1 。然而,更清楚的是分解(或“消除歧义”)那些数组并将它们包含的两个单词中的每一个分配给块变量 2 :
c.map { |aw,bw| anagram?(aw,bw) ? 1 : 0 }
#=> [0, 0, 1, 1]
传入的第一个元素是["hello", "helio"]
,所以
aw => "hello"
bw #=> "helio"
我们执行
anagram?("hello", "helio") ? 1 : 0
#=> 0
这是
的简写if anagram?("hello", "helio")
1
else
0
end
#=> 0
anagram?
方法
现在让我们转到anagram?
,
aw = "hello"
bw = "helio"
由于
aw.size == bw.size #=> true
我们不会回来。
计算第一个单词中字母的频率
现在让我写下anagram?
的下几行略有不同:
counts = Hash.new(0)
#=> {}
aw_down = aw.downcase
#=> "hello"
aw_down.each_char { |c| counts[c] += 1 }
#=> "hello"
counts
#=> {"h"=>1, "e"=>1, "l"=>2, "o"=>1}
(最后一行只是为了显示散列的值。)
在第一行中,我们创建一个默认值为零的哈希counts
。所有这些意味着,如果counts
不包含密钥k
,则counts[k]
将返回默认值。 非常重要: 这样做不会改变哈希! 3
String#each_char 4 将"hello"
的每个字符传递到块中,并将其分配给块变量c
。最初是c='h'
和h={}
。然后我们执行
counts['h'] += 1
这是
的简写counts['h'] = counts['h'] + 1
由于counts
还没有密钥'h'
,右侧的counts['h']
会返回默认值:
counts['h'] = 0 + 1 #=> 1
counts #=> {"h"=>1}
同样,在'e'
和第一个'l'
传递给块后,我们有:
counts #=> {"h"=>1, "e"=>1, "l"=>1}
但是,当我们传递第二个'l'
时,我们执行
counts['l'] = counts['l'] + 1
#=> 1 + 1
#=> 2
我们完成了
counts #=> {"h"=>1, "e"=>1, "l"=>2, "o"=>1}
方法Enumerable#each_with_object将成为好朋友
此方法仅用于保存一些步骤。它允许我们写:
counts = Hash.new(0)
aw_down.each_char { |c| counts[c] += 1 }
作为
counts = aw_down.each_with_object(Hash.new(0)) { |c,h| h[c] += 1 }
我们也可以摆脱这条线
aw_down = aw.downcase
写作
counts = aw.downcase.each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 }
这似乎是一个小小的保存,但在许多其他情况下,使用each_with_object
和其他Enumerable
类方法允许链接方法,这非常有用。
减少第二个字母中字母的字母数
提取
counts #=> {"h"=>1, "e"=>1, "l"=>2, "o"=>1}
我们现在执行
bw_down = bw.downcase
#=> "helio"
"helio".each_char do |c|
return false unless counts[c] > 0
counts[c] -= 1
end
首先,'h'
被传递到块中。作为counts['h'] #=> 1
,我们执行counts['h'] -= 1
,现在
counts #=> {"h"=>0, "e"=>1, "l"=>2, "o"=>1}`.
将'e'
和'l'
传递到块后
counts #=> {"h"=>0, "e"=>0, "l"=>1, "o"=>1}
但是当我们通过'i'
时,我们会找到
counts['i'] #=> 0
(即,返回默认值为零,我们不想将counts['i']
设置为-1
)所以我们返回false
,得出结论是这两个词是不是字谜。 (如果第二个单词是"heeio"
,当第二个false
传递给该区块时,我们会返回'e'
。)
我们有字谜吗?
由于两个单词的长度相同,如果我们能够处理第二个单词的所有字符而不返回false
,我们必须结束
counts #=> {"h"=>0, "e"=>0, "l"=>0, "o"=>0}
(无需检查!),意思是两个单词是字谜,所以在这种情况下我们会将true
返回anagrams
。 5 因此,最后一行anagram?
。
备注强>
1 在幕后,这就是发生的事情:
enum = c.map
#=> #<Enumerator: [["hello", "helio"], ["goodbye", "godbye"],
# ["pants", "Spant"], ["baa", "aba"]]:map>
在这里,我们可以看到枚举器将传递给块的元素,但有时您需要将枚举器转换为数组以获取该信息:
enum.to_a
#=> [["hello", "helio"], ["goodbye", "godbye"],
# ["pants", "Spant"], ["baa", "aba"]]
实际上,方法Array#each将enum
的元素传递到块中:
enum.each { |aw,bw| anagram?(aw,bw) ? 1 : 0 }
#=> [0, 0, 1, 1]
2 如果我们将[[1,2],3]
传递给一个块,并且块变量写为|(a,b),c|
,那么a=>1
,b=>2
,{{ 1}}。这非常方便。很酷,嗯?
3
c=>3
请注意,有一种Hash#new形式采用块,它允许在引用时不添加散列中的键。
4 而不是h = Hash.new('pig')
h['dog'] = 7 #=> 7
h #=> {"dog"=>7}
h[0] #=> "pig"
h['cat'] #=> "pig"
h[{:a=>1}] #=> "pig"
h #=> {"dog"=>7}
我们可以编写aw_down.each_char
,但aw_down.chars.each
会创建一个不必要的中间数组。 aw_down.chars
,一个枚举器,只是在需要时传递值。
5 我们可以返回each_char
而不是0
和false
而不是1
,在这种情况下我们可以写
true
a.zip(b).map { |aw,bw| anagram?(aw,bw) }
中的,但让anagrams
返回值为anagrams
或true
的数组,而不是false
或更不清楚0
?
答案 2 :(得分:0)
关于您的代码,只需要修复两件事:
x = y? do
应为if x == y
array.find(index)
您需要使用array[index]
(具体示例:a.find(z)
和b.find(z)
将分别成为a[z]
和b[z]
) 这是您的代码,应用了这两个修复程序。它works:
a = ['hello', 'goodbye', 'pants', 'baa']
b = ['helio', 'godbye', 'spant', 'aba']
x = a.length
y = b.length
z = 0
if x == y
while z < x do
if a[z].chars.sort.join == b[z].chars.sort.join
puts 1
else
puts 0
end
z += 1
end
end
有关更多ruby-idiomatic解决方案,请参阅tadman's answer。
答案 3 :(得分:0)
好的,我找到了解决方案!
for i in 0..a.length-1
a[i].chars.sort == b[i].chars.sort ? 1 : 0
end
输出
0
0
1
1