在Ruby中检索Unique

时间:2015-09-12 04:29:39

标签: ruby multidimensional-array

我目前正在使用Ruby版本1.8.7,我一直在寻找但无法找到解决方案。我目前正在创建一个独特的供应商标识符。但我会在这里简化问题。

我有供应商和产品的2D数组:

A = [["C"], ["A","D"], ["A","B"], ["B","C","E","F"], ["B","G","K"], [], ["H","I"], [], [], ["I"], ["J"]]

我需要做的是检索具有最多唯一产品数量的前5个用户(数组索引号)。在这种情况下。

前五大供应商将是:

1 - A,D
3 - B,C,E,F
4 - B,G,K
6 - H,I
10 - J

实施例

供应商3有产品["B","C","E","F"]但供应商4有产品[“B”,“G”,“K”]。
由于供应商4和3都有["B"]
供应商3有 3个独特产品 ["C","E","F"]
供应商4有 2个独特产品 ["G","K"]

我需要返回的是前五大供应商的供应商数组(基于二维数组中的索引)。

到目前为止,这是我的代码:

def test

  vendors = [[C], [A,D], [A,B], [B,C,E,F], [B,G,K], [], [H,I], [], [], [I], [J]]
  useridArr = Array(0..vendors.length-1)
  vendors = inplace_quicksort(vendors, 0, vendors.length-1,useridArr)
  getUnique(vendors,useridArr, vendors.length-1)
end

def partition_array(array, left, right, pivot_index, arr)
  pivot_value = array[pivot_index].length
  arr[pivot_index], arr[right] = arr[right], arr[pivot_index]
  array[pivot_index], array[right] = array[right], array[pivot_index]
  store_index = left

  (left..right-1).each do |i|
    if array[i].length < pivot_value
      arr[i], arr[store_index] = arr[store_index], arr[i]
      array[i], array[store_index] = array[store_index], array[i]
      store_index = store_index + 1
    end
  end

  arr[store_index], arr[right] = arr[right], arr[store_index]
  array[store_index], array[right] = array[right], array[store_index]
  return store_index
end

def inplace_quicksort(array, left, right, indexArr)
  if left < right
    pivot_index = (left + ((right - left) / 2)).to_i
    new_pivot_index = partition_array(array, left, right, pivot_index,indexArr)
    inplace_quicksort(array, left, new_pivot_index - 1,indexArr)
    inplace_quicksort(array, new_pivot_index + 1, right,indexArr)
  end
  return array
end

def getUnique(vendors,useridArr, searchFor)
  while searchFor != -1
    p vendors.map {|a| a & vendors[searchFor] }
    searchFor = searchFor - 1 
  end
end

1 个答案:

答案 0 :(得分:2)

11的每个A元素都对应一个供应商,并且(巧合)11个产品 1

A = [[:C], [:A, :D], [:A, :B], [:B, :C, :E, :F], [:B, :G, :K], [],
     [:H, :I], [], [], [:I], [:J]] 

products = A.flatten
  #=> [:C, :A, :D, :A, :B, :B, :C, :E, :F, :B, :G, :K, :H, :I, :I, :J]
products.uniq
  #=> [:C, :A, :D, :B, :E, :F, :G, :K, :H, :I, :J]
products.uniq.size
  #=> 11

我们首先计算每种产品的实例数量:

g = Hash.new(0)
counts = products.each_with_object(g) { |p,h| h[p] += 1 }
  #=> {:C=>2, :A=>2, :D=>1, :B=>3, :E=>1, :F=>1, :G=>1, :K=>1,
  #    :H=>1, :I=>2, :J=>1}

g = Hash.new(0)创建一个空哈希值,默认值为零。这意味着,如果g没有密钥k,则g[k]将返回零。注意表达式h[p] += 1。这称为缩写分配。它只是意味着表达式扩展为:

h[p] = h[p] + 1

在评估之前。如果h没有密钥p,则右侧的h[p]会返回零,因此h[p]设置为0+1 #=> 1

以上所有内容通常会更紧凑地写成如下:

counts = A.flatten.each_with_object(Hash.new(0)) { |p,h| h[p] += 1 }

仅由一家供应商提供的产品由以下人员提供:

unique_products = counts.select { |_,count| count == 1 }.keys
  #=> [:D, :E, :F, :G, :K, :H, :J]

3偏移A的供应商有两个独特的产品:E:F

[:B,:C,:E,:F] & unique_products
   #=> [:E, :F]

那是:

([:B,:C,:E,:F] & unique_products).size
   #=> 2

如果我们想要五个独特产品数量最多的供应商,按照减少数量的独特产品排序,我们可以这样做:

A.sort_by { |a| -(a & unique_products).size }.first(5)
  #=> [[:B, :G, :K], [:B, :C, :E, :F], [:H, :I], [:A, :D], [:J]]  

在Ruby 2.2+中,我们可以使用Enumerable#max_by更直接地执行此操作:

A.max_by(5) { |a| (a & unique_products).size }
  #=> [[:B, :G, :K], [:B, :C, :E, :F], [:J], [:A, :D], [:H, :I]] 

订购略有不同,但这是因为前五名的最后三家供应商都有一种独特的产品。

总结一下,我们可以写一个方法如下:

def max_unique_products(products_by_vendor, n)
  counts = products_by_vendor.flatten.
    each_with_object(Hash.new(0)) { |p,h| h[p] += 1 }
  unique_products = counts.select { |_,count| count == 1 }.keys
  products_by_vendor.max_by(n) { |a| (a & unique_products).size }
end

max_unique_products(A, 5)
  #=> [[:B, :G, :K], [:B, :C, :E, :F], [:J], [:A, :D], [:H, :I]] 

编辑1:我忘了您想要顶级供应商的索引。只需将上述方法的最后一行更改为:

products_by_vendor.each_with_index.
  max_by(n) { |a,_| (a & unique_products).size }.map(&:last)

或:

products_by_vendor.each_with_index.
  sort_by { |a,_| -(a & unique_products).size }.first(5).map(&:last)

你会得到:

max_unique_products(A, 5)
  #=> [4, 3, 10, 1, 6] 

编辑2:要使用Ruby v1.8.7,请尝试以下方法:

def max_unique_products(products_by_vendor, n)
  counts = products_by_vendor.flatten.
    reduce(Hash.new(0)) { |h,p| h[p] += 1; h }
  unique_products = counts.select { |_,count| count == 1 }.map(&:first)
  products_by_vendor.each_with_index.
    sort_by { |a,_| -(a & unique_products).size }.first(5).map(&:last)
end

它适用于v2.2,我相信所有方法都存在于v1.8.7中。

1。 OP最初将A定义为[[C],[A,D] ...]。我在答案中将其改为[[:C],[:A,:D] ...]。 lostcoder然后将其改为[[“C”],[“A”,“D”] ......]。