在Ruby中检索唯一的

在Ruby中检索唯一的,ruby,multidimensional-array,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名用户(数组索引号)。在这种情况下 前5名供应商将是: 1 - A,D 3 -

我目前使用的是Ruby版本1.8.7,我一直在四处搜索,但找不到解决方案。我目前正在创建唯一的供应商标识符。但我会在这里简化这个问题

我有一个供应商和产品的2D阵列:

A = [["C"], ["A","D"], ["A","B"], ["B","C","E","F"], ["B","G","K"], [], ["H","I"], [], [], ["I"], ["J"]]
这里我需要做的是检索拥有最多唯一产品的前5名用户(数组索引号)。在这种情况下

前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拥有两种独特的产品
[“G”、“K”]

我需要返回的是前5名供应商的供应商数组(基于他们在2D数组中的索引)

以下是我目前的代码:

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
def测试
供应商=[[C]、[A、D]、[A、B]、[B、C、E、F]、[B、G、K]、[H、I]、[]、[]、[I]、[J]]
useridArr=数组(0..vendors.length-1)
vendors=inplace\u快速排序(vendors,0,vendors.length-1,useridArr)
getUnique(供应商、用户IDARR、供应商。长度-1)
结束
def分区数组(数组、左、右、轴索引、arr)
pivot\u值=数组[pivot\u索引].长度
arr[pivot_index],arr[right]=arr[right],arr[pivot_index]
数组[pivot_index],数组[right]=数组[right],数组[pivot_index]
存储索引=左
(左..右-1)。每个都有|
如果数组[i]。长度<枢轴值
arr[i],arr[store_index]=arr[store_index],arr[i]
数组[i],数组[store\u index]=数组[store\u index],数组[i]
存储索引=存储索引+1
结束
结束
arr[store_index],arr[right]=arr[right],arr[store_index]
数组[存储索引],数组[右]=数组[右],数组[存储索引]
返回存储索引
结束
def就地快速排序(数组、左、右、索引)
如果左<右
pivot_index=(左+((右-左)/2))。到_i
新建轴索引=分区数组(数组、左、右、轴索引、索引)
就地快速排序(数组,左侧,新的轴索引-1,indexArr)
就地快速排序(数组,新的轴索引+1,右,indexArr)
结束
返回数组
结束
def getUnique(供应商、用户IDARR、搜索)
搜索时!=-1.
p vendors.map{| a | a&vendors[searchFor]}
searchFor=searchFor-1
结束
结束

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

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

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 }
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]] 
只有一家供应商提供的产品由以下供应商提供:

unique_products = counts.select { |_,count| count == 1 }.keys
  #=> [:D, :E, :F, :G, :K, :H, :J]
A
中偏移量
3
处的供应商有两种独特的产品,
: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+中,我们可以更直接地使用:

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

最后,我们可以编写如下方法:

counts = A.flatten.each_with_object(Hash.new(0)) { |p,h| h[p] += 1 }
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)
或:

您将获得:

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中


一,。OP最初将A定义为[[C],[A,D]…]。在我的回答中,我把它改为[:C],:A,:D]…]。lostcoder随后将其更改为[[“C”]、[“A”、“D”]…]

很抱歉,如果不够清楚,索引0
[C]
已存在于索引3中。从某种意义上说,索引3中的供应商涵盖的产品比索引0中的产品更多。因此,将选择具有
[B、C、E、F]
的供应商。希望这能有所帮助。但是非常感谢您的及时回复!迷失了,不要因为我的代码比你的短得多而沮丧。这种情况会发生在每一个刚接触编程或者从一种不太具描述性的语言来到Ruby的人身上。当你获得Ruby的知识并磨练你的技能时,把它看作是你必须期待的。嗨,Cary,谢谢你的帮助。我理解你逻辑背后的概念和思维过程,必须说这对我帮助很大。然而,我需要返回的是拥有最多独特产品的用户的索引。我真的不知道该怎么表达。但是如果你提到上面,我应该返回
[1,3,4,6,10]
。另外,我目前正在使用Ruby 1.8.7,其中有些方法不可用。这方面有什么办法吗?再一次,非常感谢。我真的很感激,伊加德!1.8.7!!?? 为什么?它肯定有10年了。我编辑了答案的结尾,以返回顶级供应商的索引。嗨,Cary,我客户的要求是1.8.7(也不知道为什么),但我别无选择。非常感谢您提供的解决方案,并尝试现在就理解它!我已经实现了
reduce
但是
unique_products=counts.select{|,count | count==1}。keys
给了我一个
NoMethodError:undefined method keys
。我做了一个编辑,提供了一个应该与Ruby v.1.8.7一起使用的版本。查看我如何使用
reduce
。您是否忘记切换块变量的顺序或添加
;h
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