ruby 删除数组中的重复元素,该数组是散列及其对应ID中的值

guz6ccqo  于 2023-10-17  发布在  Ruby
关注(0)|答案(3)|浏览(172)

我有一个散列值,它是一个数组。如何以最高效的方式删除数组中重复的元素和对应的id?
这是我的哈希值的一个例子

hash = { 
  "id" => "sjfdkjfd",
  "name" => "Field Name",
  "type" => "field",
  "options" => ["Language", "Question", "Question", "Answer", "Answer"],
  "option_ids" => ["12345", "23456", "34567", "45678", "56789"]
}

我的想法是这样的

hash["options"].each_with_index { |value, index |
  h = {}
  if h.key?(value)
    delete(value)
    delete hash["option_ids"].delete_at(index)
  else 
    h[value] = index
  end
}

结果应该是

hash = { 
  "id" => "sjfdkjfd",
  "name" => "Field Name",
  "type" => "field",
  "options" => ["Language", "Question", "Answer"],
  "option_ids" => ["12345", "23456", "45678"]
}

我知道我必须考虑到,当我删除选项和option_id的值时,这些值的索引将发生变化。但不知道该怎么做

v1l68za4

v1l68za41#

我的第一个想法是压缩值并调用uniq,然后想办法返回到初始形式:

h['options'].zip(h['option_ids']).uniq(&:first).transpose
#=> [["Language", "Question", "Answer"], ["12345", "23456", "45678"]]

然后,通过并行分配:

h['options'], h['option_ids'] = h['options'].zip(h['option_ids']).uniq(&:first).transpose

h #=> {"id"=>"sjfdkjfd", "name"=>"Field Name", "type"=>"field", "options"=>["Language", "Question", "Answer"], "option_ids"=>["12345", "23456", "45678"]}

这些是步骤:

h['options'].zip(h['option_ids'])
#=> [["Language", "12345"], ["Question", "23456"], ["Question", "34567"], ["Answer", "45678"], ["Answer", "56789"]]

h['options'].zip(h['option_ids']).uniq(&:first)
#=> [["Language", "12345"], ["Question", "23456"], ["Answer", "45678"]]
ubby3x7f

ubby3x7f2#

hash = { 
  "id" => "sjfdkjfd",
  "name" => "Field Name",
  "type" => "field",
  "options" => ["L", "Q", "Q", "Q", "A", "A", "Q"],
  "option_ids" => ["12345", "23456", "34567", "dog", "45678", "56789", "cat"]
}

我假设“重复的元素”指的是连续的相等元素(仅在[1,2,2,1]中有2),而不是“重复的元素”(在前面的例子中有12)。我展示了如果第二种解释适用,代码将如何被修改(实际上是简化)。

idx = hash["options"].
  each_with_index.
  chunk_while { |(a,_),(b,_)| a==b }.
  map { |(_,i),*| i }
  #=> [0, 1, 4, 6]

hash.merge(
  ["options", "option_ids"].each_with_object({}) { |k,h| h[k] = hash[k].values_at(*idx) }
)
  #=> {"id"=>"sjfdkjfd",
  #    "name"=>"Field Name",
  #    "type"=>"field",
  #    "options"=>["L", "Q", "A", "Q"],
  #    "option_ids"=>["12345", "23456", "45678", "cat"]}

如果“重复元素”被解释为"options""option_ids"的值仅具有上面显示的前三个元素,则计算idx如下:

idx = hash["options"].
  each_with_index.
  uniq { |s,_| s }.
  map(&:last)
    #=> [0, 1, 4]

请参阅EQUIPMENT #chunk_while(EQUIPMENT #slice_when可以改为)和Array#values_at。其步骤如下。

a = hash["options"]
  #=> ["L", "Q", "Q", "Q", "A", "A", "Q"] 
e0 = a.each_with_index
  #=> #<Enumerator: ["L", "Q", "Q", "Q", "A", "A", "Q"]:each_with_index> 
e1 = e0.chunk_while { |(a,_),(b,_)| a==b }
  #=> #<Enumerator: #<Enumerator::Generator:0x000055e4bcf17740>:each>

我们可以看到枚举器e1将生成并通过将其转换为数组传递给map的值:

e1.to_a
  #=> [[["L", 0]],
  #    [["Q", 1], ["Q", 2], ["Q", 3]],
  #    [["A", 4], ["A", 5]], [["Q", 6]]]

继续

idx = e1.map { |(_,i),*| i }
  #=> [0, 1, 4, 6] 

c = ["options", "option_ids"].
      each_with_object({}) { |k,h| h[k] = hash[k].values_at(*idx) } 
  #=> {"options"=>["L", "Q", "A", "Q"],
  #    "option_ids"=>["12345", "23456", "45678", "cat"]} 
hash.merge(c)
  #=> {"id"=>"sjfdkjfd",
  #    "name"=>"Field Name",
  #    "type"=>"field",
  #    "options"=>["L", "Q", "A", "Q"],
  #    "option_ids"=>["12345", "23456", "45678", "cat"]}
gfttwv5a

gfttwv5a3#

使用Array#transpose

hash = {
  "options" => ["Language", "Question", "Question", "Answer", "Answer"],
  "option_ids" => ["12345", "23456", "34567", "45678", "56789"]
}

hash.values.transpose.uniq(&:first).transpose.map.with_index {|v,i| [hash.keys[i], v]}.to_h
#=> {"options"=>["Language", "Question", "Answer"], "option_ids"=>["12345", "23456", "45678"]}

OP编辑后:

hash = {
  "id" => "sjfdkjfd",
  "name" => "Field Name",
  "type" => "field",
  "options" => ["Language", "Question", "Question", "Answer", "Answer"],
  "option_ids" => ["12345", "23456", "34567", "45678", "56789"]
}

hash_array = hash.to_a.select {|v| v.last.is_a?(Array)}.transpose
hash.merge([hash_array.first].push(hash_array.last.transpose.uniq(&:first).transpose).transpose.to_h)
#=> {"id"=>"sjfdkjfd", "name"=>"Field Name", "type"=>"field", "options"=>["Language", "Question", "Answer"], "option_ids"=>["12345", "23456", "45678"]}

相关问题