I have two arrays of hashes that look something like this:
我有两个哈希数组,看起来像这样:
h1=[{id:1, item:1, value:10},
{id:1, item:2, value:3}]
h2=[{id:1, item_a:1, value:5},{id:2, item_a:1, value:7},{id:3, item_a:1, value:10},
{id:4, item_b:2, value:1},{id:5, item_b:2, value:2},{id:6, item_b:2, value:5},
{id:7, item_b:2, value:1}]
I need to iterate through h2
and:
我需要遍历h2和:
- for each
h1
hash, find anh2
hash whoseitem
corresponds toitem_a
, e.g.,item
value is1
anditem_a
values is1
, - take
value
from hashh2
until sum of the items taken are equal to or bigger than the one inh1
hashvalue
, - create an array of arrays of ids from
h1
andh2
whose first value isid
fromh1
and second value isid
fromh2
.
对于每个h1哈希,找到其项目对应于item_a的h2哈希,例如,项值为1且item_a值为1,
从哈希值h2获取值,直到所采用的项的总和等于或大于h1哈希值中的项,
从h1和h2创建一个id数组数组,其第一个值是来自h1的id,第二个值是来自h2的id。
In my example above, the result would be [[1,1],[1,2],[1,4],[1,5]]
.
在我上面的例子中,结果将是[[1,1],[1,2],[1,4],[1,5]]。
I've found this answer here, however it just sums up the values up to some defined limit. I don't know how to take the values until some total sum is reached part. I hope someone can give me direction where I should be looking at.
我在这里找到了这个答案,但它只是将值总结到某个定义的限制。我不知道如何获取值,直到达到总和的一部分。我希望有人可以指导我应该关注的方向。
Update
Result [[1,1],[1,2],[1,4],[1,5]]
is because:
结果[[1,1],[1,2],[1,4],[1,5]]是因为:
- from
h1
we take first hash whereitem:1
andvalue:10
, so we need to collect ids fromh2
whereitem_a:1
since I need1
and1
values (in real life - ids) and our total value should be at least10
- we iterate through
h2
and start by first hash - itsvalue:5
which is smaller than10
so we take it and we go to next hash - itsvalue:7
and if we sum it to previously taken5
, we get12
- it is bigger than10
so we take it and stop iteration here as we are not allowed to take any more item. Our result for first iteration is: id fromh1
hash is1
and ids fromh2
hash are1
and2
. So our array so far is[[1,1],[1,2]]
- we do same thing for second hash from
h1
, where our matched ids fromh2
are4
and5
.
从H1我们把其中项目第一哈希:1和值:10,所以我们需要从那里item_a H2收集IDS:1,因为我需要1倍1的值(在现实生活中 - IDS)和我们的总价值至少应为10
我们迭代h2并从第一个哈希开始 - 它的值:5小于10所以我们接受它并且我们转到下一个哈希 - 它的值:7如果我们将它加到之前的5,我们得到12 - 它是大于10所以我们采取它并停止迭代,因为我们不允许再采取任何项目。我们的第一次迭代的结果是:来自h1哈希的id是1,来自h2哈希的id是1和2.所以到目前为止我们的数组是[[1,1],[1,2]]
我们对来自h1的第二个哈希做同样的事情,其中我们匹配的来自h2的id是4和5。
Update 2
I'm clearing out my example as there can be simply item
in both hashes. I'd like to expand a bit my example.
我正在清理我的例子,因为两个哈希中都可以有简单的项目。我想扩展我的例子。
How would code change if extra criteria from
-to
date range and date
criteria would be added in h1
and h2
?
如果在h1和h2中添加额外的标准从最新范围和日期标准,代码将如何变化?
h1=[{id:1, item:1, from: DateTime.new(2017,9,4,6,0,0,'+0300'), to: DateTime.new(2017,9,4,17,59,59,'+0300'), value:10},
{id:1, item:2, from: DateTime.new(2017,9,4,18,0,0,'+0300'), to: DateTime.new(2017,9,4,23,59,59,'+0300'), value:10}]
h2=[{id:1, item:1, date: DateTime.new(2017,9,4,6,10,0,'+0300'), value:5},
{id:2, item:1, date: DateTime.new(2017,9,4,7,20,0,'+0300'), value:7},
{id:3, item:1, date: DateTime.new(2017,9,4,8,05,0,'+0300'), value:10},
{id:4, item:2, date: DateTime.new(2017,9,4,18,19,10,'+0300'), value:1},
{id:5, item:2, date: DateTime.new(2017,9,4,19,20,0,'+0300'), value:2},
{id:6, item:2, date: DateTime.new(2017,9,4,22,22,0,'+0300'), value:5},
{id:7, item:2, date: DateTime.new(2017,9,4,23,0,0,'+0300'), value:1}]
I'd like to take ids from only those hashes where date
from h2
is in range of h1
dates in from
- to
. I assume I should put this h2[:date].between?(h1[:from], h1[:to])
somewhere.
我想从只有那些哈希的日期中获取ids,其中h2的日期在h1的范围内,从 - 到。我想我应该把这个h2 [:date]。between?(h1 [:from],h1 [:to])放在某个地方。
2 个解决方案
#1
2
First off a couple assumptions I'm making, you don't mention item_b
at all in your description, and only state that the link between h1
and h2
is the key item_a
, so I'm assuming that item_a
and item_b
are equivalent...ie, you won't have something like item_b: 1
that you wouldn't want to consider for the first hash in h1
just because it's item_b
and not item_a
. If that's not correct, you'll need to adjust the code below accordingly (shouldn't be too difficult).
首先是我正在做的几个假设,你在描述中根本没有提到item_b,并且只说明h1和h2之间的链接是关键item_a,所以我假设item_a和item_b是等价的。 .ie,你不会有类似item_b:1的东西,你不想考虑h1中的第一个哈希只是因为它是item_b而不是item_a。如果这不正确,您需要相应地调整下面的代码(不应该太难)。
To start with, it will be easier if you group the items in h2
by their item_a/item_b
keys so you can just do a simple look up for them:
首先,如果您通过item_a / item_b键对h2中的项目进行分组会更容易,这样您就可以进行简单的查找:
h2 = h2.group_by { |item| item[:item_a] || item[:item_b] }
# => {1=>[ {:id=>1, :item_a=>1, :value=>5},
{:id=>2, :item_a=>1, :value=>7},
{:id=>3, :item_a=>1, :value=>10} ],
2=>[ {:id=>4, :item_b=>2, :value=>1},
{:id=>5, :item_b=>2, :value=>2},
{:id=>6, :item_b=>2, :value=>5},
{:id=>7, :item_b=>2, :value=>1} ]
}
Now, h2[1]
has all the items that map to the first row of h1
(based on the item
key). Next, you want to map the values from h1
into a list of array with the id
from h1
and the id
from h2
and the id
s from h2
come from a take_while
loop, keeping track of a sum:
现在,h2 [1]具有映射到h1的第一行的所有项目(基于项目键)。接下来,您希望将h1中的值映射到一个数组列表,其中id为h1,id来自h2,而来自h2的id来自take_while循环,跟踪总和:
results = h1.map do |base|
sum = 0
h2[base[:item]].take_while do |item|
sum += item[:value] if sum < base[:value]
end.map do |item|
[base[:id], item[:id]]
end
end
# => [[[1, 1], [1, 2]], [[1, 4], [1, 5]]]
Lastly, you'll need to flatten by 1 level to get the result you want:
最后,你需要压平1级才能得到你想要的结果:
puts results.flatten(1).inspect
# => [[1, 1], [1, 2], [1, 4], [1, 5]]
#2
1
I too have questions about the keys :item_a
and :item_b
(and presumably :item_c
, etc.) in h2
. One could assume :item_a
pertains to h1[0]
, :item_b
to h1[1]
, and so on, but it's easier to just give them all the same name, which I've chosen to be :item
. That is, having item_a
and item_b
does not make it a more difficult problem, it just introduces a nuisance from a coding standpoint.
我也对h2中的键:item_a和:item_b(以及大概:item_c等)有疑问。可以假设:item_a属于h1 [0],:item_b到h1 [1],依此类推,但更容易给它们所有相同的名称,我选择它:item。也就是说,如果item_a和item_b没有使它成为一个更难的问题,它只是从编码的角度引入了一个麻烦。
h1 = [{ id:1, item:1, value:10 }, { id:1, item:2, value:3 }]
h2 = [{ id:1, item:1, value:5 }, { id:2, item:1, value:7 }, { id:3, item:1, value:10 },
{ id:4, item:2, value:1 }, { id:5, item:2, value:2 }, { id:6, item:2, value:5},
{ id:7, item:2, value:1 }]
I have assumed that, for each hash g
in h1
, if g[:value]
is greater than the sum of f[:value]
over all hashes f
in h2
for which f[:item] = g[:item]
, [g[:id], f[:id]
, for all such hashes f
, would be included in the array that is returned. (Whew!) If, instead, g
should simply be disregarded is the sum of values from h2
insufficient, that requires only a small change to the code below.
我假设,对于h1中的每个散列g,如果g [:value]大于f [:value]与h2中所有散列f之和f [:item] = g [:item],[对于所有这样的散列f,g [:id],f [:id]将包含在返回的数组中。 (哇!)如果相反,g应该被忽略,那么来自h2的值的总和就不足了,这只需要对下面的代码进行一些小改动。
The first step is to construct another hash from h2
.
第一步是从h2构造另一个哈希。
h = h2.each_with_object({}) do |g, h|
h.update(g[:item]=>[[g[:id], g[:value]]]) do |_, o, n|
o << [g[:id], o.last.last + g[:value]]
end
end
#=> {1=>[[1, 5], [2, 12], [3, 22]], 2=>[[4, 1], [5, 3], [6, 8], [7, 9]]}
As you see, h
has keys equal to the values of :item
and values that are arrays of pairs of :id
values and "cumulative" values of :value
.
如您所见,h的键值等于:item和值,它们是成对的数组:id值和value的“累积”值。
h1.each_with_object([]) do |g, a|
id1 = g[:id]
value1 = g[:value]
arr = h[g[:item]]
i = arr.index { |_id2, cum| value1 <= cum } || (arr.size - 1)
arr[0..i].map(&:first).each { |id2| a << [id1, id2] }
end
#=> [[1, 1], [1, 2], [1, 4], [1, 5]]
The steps following the calculation of h
are as follows.
计算h后的步骤如下。
a = []
g = { id:1, item:1, value:10 }
id1 = g[:id]
#=> 1
value1 = g[:value]
#=> 10
arr = h[g[:item]]
#=> h[1]
#=> [[1, 5], [2, 12], [3, 22]]
i = arr.index { |_id2, cum| value1 <= cum } || (arr.size - 1)
#=> 1
If value1
had been, say 100
, we would obtain arr.index { |_id2, cum| value1 <= cum } #=> nil
. In this case i
is set equal to the "or'ed" term arr.size - 1
.
如果value1已经是100,我们将获得arr.index {| _id2,cum | value1 <= cum}#=> nil。在这种情况下,我被设置为等于“or'ed”术语arr.size - 1。
b = arr[0..i]
#=> [[1, 5], [2, 12]]
c = b.map(&:first)
#=> [1, 2]
c.each { |id2| a << [id1, id2] }
a #=> [[1, 1], [1, 2]]
The remaining calculations are similar.
剩下的计算是类似的。
#1
2
First off a couple assumptions I'm making, you don't mention item_b
at all in your description, and only state that the link between h1
and h2
is the key item_a
, so I'm assuming that item_a
and item_b
are equivalent...ie, you won't have something like item_b: 1
that you wouldn't want to consider for the first hash in h1
just because it's item_b
and not item_a
. If that's not correct, you'll need to adjust the code below accordingly (shouldn't be too difficult).
首先是我正在做的几个假设,你在描述中根本没有提到item_b,并且只说明h1和h2之间的链接是关键item_a,所以我假设item_a和item_b是等价的。 .ie,你不会有类似item_b:1的东西,你不想考虑h1中的第一个哈希只是因为它是item_b而不是item_a。如果这不正确,您需要相应地调整下面的代码(不应该太难)。
To start with, it will be easier if you group the items in h2
by their item_a/item_b
keys so you can just do a simple look up for them:
首先,如果您通过item_a / item_b键对h2中的项目进行分组会更容易,这样您就可以进行简单的查找:
h2 = h2.group_by { |item| item[:item_a] || item[:item_b] }
# => {1=>[ {:id=>1, :item_a=>1, :value=>5},
{:id=>2, :item_a=>1, :value=>7},
{:id=>3, :item_a=>1, :value=>10} ],
2=>[ {:id=>4, :item_b=>2, :value=>1},
{:id=>5, :item_b=>2, :value=>2},
{:id=>6, :item_b=>2, :value=>5},
{:id=>7, :item_b=>2, :value=>1} ]
}
Now, h2[1]
has all the items that map to the first row of h1
(based on the item
key). Next, you want to map the values from h1
into a list of array with the id
from h1
and the id
from h2
and the id
s from h2
come from a take_while
loop, keeping track of a sum:
现在,h2 [1]具有映射到h1的第一行的所有项目(基于项目键)。接下来,您希望将h1中的值映射到一个数组列表,其中id为h1,id来自h2,而来自h2的id来自take_while循环,跟踪总和:
results = h1.map do |base|
sum = 0
h2[base[:item]].take_while do |item|
sum += item[:value] if sum < base[:value]
end.map do |item|
[base[:id], item[:id]]
end
end
# => [[[1, 1], [1, 2]], [[1, 4], [1, 5]]]
Lastly, you'll need to flatten by 1 level to get the result you want:
最后,你需要压平1级才能得到你想要的结果:
puts results.flatten(1).inspect
# => [[1, 1], [1, 2], [1, 4], [1, 5]]
#2
1
I too have questions about the keys :item_a
and :item_b
(and presumably :item_c
, etc.) in h2
. One could assume :item_a
pertains to h1[0]
, :item_b
to h1[1]
, and so on, but it's easier to just give them all the same name, which I've chosen to be :item
. That is, having item_a
and item_b
does not make it a more difficult problem, it just introduces a nuisance from a coding standpoint.
我也对h2中的键:item_a和:item_b(以及大概:item_c等)有疑问。可以假设:item_a属于h1 [0],:item_b到h1 [1],依此类推,但更容易给它们所有相同的名称,我选择它:item。也就是说,如果item_a和item_b没有使它成为一个更难的问题,它只是从编码的角度引入了一个麻烦。
h1 = [{ id:1, item:1, value:10 }, { id:1, item:2, value:3 }]
h2 = [{ id:1, item:1, value:5 }, { id:2, item:1, value:7 }, { id:3, item:1, value:10 },
{ id:4, item:2, value:1 }, { id:5, item:2, value:2 }, { id:6, item:2, value:5},
{ id:7, item:2, value:1 }]
I have assumed that, for each hash g
in h1
, if g[:value]
is greater than the sum of f[:value]
over all hashes f
in h2
for which f[:item] = g[:item]
, [g[:id], f[:id]
, for all such hashes f
, would be included in the array that is returned. (Whew!) If, instead, g
should simply be disregarded is the sum of values from h2
insufficient, that requires only a small change to the code below.
我假设,对于h1中的每个散列g,如果g [:value]大于f [:value]与h2中所有散列f之和f [:item] = g [:item],[对于所有这样的散列f,g [:id],f [:id]将包含在返回的数组中。 (哇!)如果相反,g应该被忽略,那么来自h2的值的总和就不足了,这只需要对下面的代码进行一些小改动。
The first step is to construct another hash from h2
.
第一步是从h2构造另一个哈希。
h = h2.each_with_object({}) do |g, h|
h.update(g[:item]=>[[g[:id], g[:value]]]) do |_, o, n|
o << [g[:id], o.last.last + g[:value]]
end
end
#=> {1=>[[1, 5], [2, 12], [3, 22]], 2=>[[4, 1], [5, 3], [6, 8], [7, 9]]}
As you see, h
has keys equal to the values of :item
and values that are arrays of pairs of :id
values and "cumulative" values of :value
.
如您所见,h的键值等于:item和值,它们是成对的数组:id值和value的“累积”值。
h1.each_with_object([]) do |g, a|
id1 = g[:id]
value1 = g[:value]
arr = h[g[:item]]
i = arr.index { |_id2, cum| value1 <= cum } || (arr.size - 1)
arr[0..i].map(&:first).each { |id2| a << [id1, id2] }
end
#=> [[1, 1], [1, 2], [1, 4], [1, 5]]
The steps following the calculation of h
are as follows.
计算h后的步骤如下。
a = []
g = { id:1, item:1, value:10 }
id1 = g[:id]
#=> 1
value1 = g[:value]
#=> 10
arr = h[g[:item]]
#=> h[1]
#=> [[1, 5], [2, 12], [3, 22]]
i = arr.index { |_id2, cum| value1 <= cum } || (arr.size - 1)
#=> 1
If value1
had been, say 100
, we would obtain arr.index { |_id2, cum| value1 <= cum } #=> nil
. In this case i
is set equal to the "or'ed" term arr.size - 1
.
如果value1已经是100,我们将获得arr.index {| _id2,cum | value1 <= cum}#=> nil。在这种情况下,我被设置为等于“or'ed”术语arr.size - 1。
b = arr[0..i]
#=> [[1, 5], [2, 12]]
c = b.map(&:first)
#=> [1, 2]
c.each { |id2| a << [id1, id2] }
a #=> [[1, 1], [1, 2]]
The remaining calculations are similar.
剩下的计算是类似的。