在Ruby中的哈希值中查找数组的类似元素

时间:2014-10-23 02:24:29

标签: ruby arrays hash

我有以下哈希:

hash = {"One" => [1,2,3,4], "Two" => [1,5,6,7], "Three" => [1,8,9,10]}

如果哈希中每个数组的第一个元素以1开头,则放置字符串的条件语句。

if hash.values.all?{|array| array[0] == 1}
  puts "Hello World"
end

有没有办法改变输入的块以检查共享相同索引的值的所有组合是否也共享相同的值?

示例:

hash = {"One" => [4,1,3,11], "Two" => [14,1,6,7], "Three" => [12,1,9,10]}

if hash.values.all?{|array| array[0 or 1 or 2 or 3] == 1} (I know this is not valid Ruby code)
  puts "Hello World"
end

更新

hash [“One”],hash [“Two”]和hash [“Three”]目前都包含数组作为它们的值。在它们的数组中,元素1位于它们[1]索引位置的每一个中。我需要运行一个条件语句,其中如果一个元素(如1)位于多个数组的相同索引位置,每个数组都嵌套为哈希中键的值,则会放置一个字符串。请注意,元素必须位于每个数组中且位于相同的索引位置才能传递。

hash = {"One" => [1,2,3,4], "Two" => [1,5,6,7], "Three" => [1,8,9,10]} # => True, 1 is in the [0] position for each array

hash = {"One" => [1,2,3,4], "Two" => [15,5,6,7], "Three" => [1,8,9,10]} # => Fail, 1 doesn't exist in the second array

hash = {"One" => [1,2,3,4], "Two" => [4,1,6,7], "Three" => [1,8,9,10]} # => Fail, 1 exists in the [0] position of the first and third array but [1] in the second array

hash = {"One" => [4,1,3,4], "Two" => [9,1,6,7], "Three" => [55,1,9,10]} # => True, 1 is in the [1] position for each array

1 个答案:

答案 0 :(得分:2)

这是一种有趣的方法,可以确保所有阵列在插槽中至少有一个具有相同值的插槽:

hash = {"One" => [4,1,3,11], "Two" => [14,1,6,7], "Three" => [12,1,9,10]}
if hash.values.transpose.map(&:uniq).any?{ |a| a.length==1 }
  # at least one of the 'slots' has all the same value
end

要清楚,此代码将匹配以下任一项:

a = { one:[8,9,6], two:[1,9,2], three:[0,9,0] }
b = { one:[7,7,7], two:[6,6,7], three:[4,3,7] }

...因为在这两种情况下都有一个'slot'在所有数组中具有相同的值。 (在a中,第二个广告位均为9,在b中,第三个广告位均为7。)

不匹配:

c = { one:[1,1,1], two:[2,2,2], three:[3,3,3] }

因为虽然每个数组都有相同的值,但每个相应插槽中的值都是唯一的,即每个索引的[1,2,3]


或者,如果值不仅必须相同,而是该指数的值 - 即。第一个索引为0,第二个索引为1,依此类推 - 您可以这样做:

if hash.values.transpose.map(&:uniq).select.with_index{ |a,i| a.length==1 && a.first==i }.first
  # at least one of the 'slots' is consistently filled with
  # a value that is the index of the slot
end

在这种情况下,abc都不会匹配,但这样会:

d = { one:[3,4,2,6], two:[8,1,2,2], three:[9,6,2,4] }

...因为第三个广告位(索引#2)中总是有一个2

类似的(可以说是更容易理解的)技术将是:

if hash.values.transpose.to_enum(:any?).with_index{ |a,i| a.all?{ |n| n==i } }
  # yay!
end

说明

根据要求,让我们通过查看电话和临时值来理解这些答案:

解决方案#1 - 任何插槽都具有相同的值(任何值)

hash = {"One" => [4,1,3,11], "Two" => [14,1,6,7], "Three" => [12,1,9,10]}

# Get an array of just the value parts of the hash
hash.values   
#=> [ [4,1,3,11], [14,1,6,7], [12,1,9,10] ]

# 'Rotate' the array of arrays, swapping 'rows' and 'columns'
hash.values.transpose  
#=> [ [4,14,12], [1,1,1], [3,6,9], [11,7,10] ] 

# Convert each of the new arrays to the set of distinct values in the array
# Equivalent to hash.values.transpose.map{ |a| a.uniq }
hash.values.transpose.map(&:uniq)
#=> [ [4,14,12], [1], [3,6,9], [11,7,10] ] 

# Test to see if any of these arrays has only one value in it
# i.e. If the array started out with all the same values
hash.values.transpose.map(&:uniq).any?{ |a| a.length==1 }
#=> true    (the second array-of-unique-values has only one element)

解决方案2a:任何插槽都具有该索引处的所有值

我们上面已经介绍了hash.values.transpose.map(&:uniq),所以我们将从那里开始:

slot_values = hash.values.transpose.map(&:uniq)

# Create an Enumerator that selects items
# Normally select would take a block and return the matching values;
# When called without a block it gives you a 'delayed' form, the Enumerator
slot_values.select
#=> #<Enumerator: [[4,14,12],[1,1,1],[3,6,9],[11,7,10]]:any?>

# Add an index to the values during enumeration
slot_values.select.with_index
#=> #<Enumerator: #<Enumerator: [[4,14,12],[1,1,1],[3,6,9],[11,7,10]]:any?>:with_index>

# Invoke the enumerator, getting passed an array and the index
# Choose to select the array only if it has one element,
# and that element is the same value as the current index
slot_values.select.with_index{ |a,i| a.length==1 && a.first==i }
#=> [[1]]

# `.first` will return `nil` if the select returned no results,
# or the first array if there was at least one result.
# Because `nil` is considered "non-truthy", but an array is "truthy"
# We can use this as the condition for our if statement:
if slot_values.select.with_index{ |a,i| a.length==1 && a.first==i }.first
#=> …we enter the if statement because `.first` returns `[1]`…

解决方案2b:任何插槽都具有该索引处的所有值

我们将从转置值开始:

slotvals = hash.values.transpose
#=> [ [4,14,12], [1,1,1], [3,6,9], [11,7,10] ] 

# Create an Enumerator (delayed evaluation) of the `any?` method
slotvals.to_enum(:any?)
#=> #<Enumerator: [[4,14,12],[1,1,1],[3,6,9],[11,7,10]]:any?>

# Add an index to the values that will be yielded to the enumerator
slotvals.to_enum(:any?).with_index
#=> #<Enumerator: #<Enumerator: [[4,14,12],[1,1,1],[3,6,9],[11,7,10]]:any?>:with_index>

# Invoke the enumerator, getting passed the array of slot values and the slot index
# For each array/index see if every value of the array equals the slot index
slotvals.to_enum(:any?).with_index{ |a,i| a.all?{ |n| n==i } }
#=> true  (bc the second array was all 1 values, which matched the array's index)

有关枚举数的更多详细信息,请阅读documentation on Enumerator