所以这是一个问题。我想要做的是在给定一组输入值的情况下生成数据结构。
由于这是一个多语言提交,让我们将输入列表视为键/值对的数组。因此,哈希,地图,字典或任何浮动你的船的术语的数组。我将这里的所有符号都保留为JSON,希望它具有足够的通用性来翻译/解码。
所以对于输入,假设我们有这个:
[ { "4": 10 }, { "7": 9 }, { "90": 7 }, { "1": 8 } ]
也许有点多余,但让我们坚持下去。
所以从那个输入来看,我想要达到这个结构。我给出了一个完整的结构,但重要的部分是“weight”下的值返回的内容:
[
{ "$project": {
"user_id": 1,
"content": 1,
"date": 1,
"weight": { "$cond": [
{ "$eq": ["$user_id": 4] },
10,
{ "$cond": [
{ "$eq": ["$user_id": 7] },
9,
{ "$cond": [
{ "$eq": ["$user_id": 90] },
7,
{ "$cond": [
{ "$eq": ["$user_id": 1] },
8,
0
]}
]}
]}
]}
}}
]
所以我正在寻找的解决方案通过使用输入来填充“重量”的结构内容,如结构所示。
是结构中看起来像数字的值必须是数字而不是字符串,因此无论语言实现如何,JSON编码版本必须看起来完全相同。
或者,给我一个更好的方法来获得基于匹配user_id
分配权重值的相同结果。
有没有人对此有所了解?
对任何语言实现都会感到满意,因为我认为只看到如何创建结构是公平的。
我会尝试添加自己,但荣誉归功于良好的实现。
快乐的编码。
答案 0 :(得分:2)
当我有时间考虑这个问题时,我跑回到perl并将其解决了:
use Modern::Perl;
use Moose::Autobox;
use JSON;
my $encoder = JSON->new->pretty;
my $input = [ { 4 => 10 }, { 7 => 9 }, { 90 => 7 }, { 1 => 8 } ];
my $stack = [];
foreach my $item ( reverse @{$input} ) {
while ( my ( $key, $value ) = each %{$item} ) {
my $rec = {
'$cond' => [
{ '$eq' => [ '$user_id', int($key) ] },
$value
]
};
if ( $stack->length == 0 ) {
$rec->{'$cond'}->push( 0 );
} else {
my $last = $stack->pop;
$rec->{'$cond'}->push( $last );
}
$stack->push( $rec );
}
}
say $encoder->encode( $stack->[0] );
所以这个过程非常简单。
浏览数组中的每个项目并获取条目的键和值
创建一个新的“文档”,该文档在“$ cond”键的数组参数中只包含两个必需的三个条目。这些是分配用于测试“$ user_id”和返回的“权重”值的值。
测试堆栈的外部变量的长度,如果它是空的(第一次通过),则推送 0
的值在最后一个嵌套元素中看到文档中“$ cond”键的结尾。
如果已经存在某些内容(长度> 0),则将该值和推送作为文档“$ cond”键中的第三个值。
将该文件作为堆叠的值重新放入,并重复下一个项目
因此,列表中有一些内容,例如反转输入的顺序,这不是必需的,但会在嵌套输出中产生自然顺序。另外,我对外部“堆栈”的选择是一个数组,因为测试运算符看起来很简单。但它确实只是一个单一的价值,不断被重复使用,增加和替换。
此外,JSON打印仅用于显示输出。所有真正需要的是将堆栈的结果值合并到结构中。
然后我将逻辑转换为ruby,就像OP使用的语言一样,我从中获得了如何生成这种嵌套结构的灵感:
require 'json'
input = [ { 4 => 10 }, { 7 => 9 }, { 90 => 7 }, { 1 => 8 } ]
stack = []
input.reverse_each {|item|
item.each {|key,value|
rec = {
'$cond' => [
{ '$eq' => [ '$user_id', key ] },
value
]
}
if ( stack.length == 0 )
rec['$cond'].push( 0 )
else
last = stack.pop
rec['$cond'].push( last )
end
stack.push( rec )
}
}
puts JSON.pretty_generate(stack[0])
然后最终进入最终形式以生成OP想要的管道:
require 'json'
userWeights = [ { 4 => 10 }, { 7 => 9 }, { 90 => 7}, { 1 => 8 } ]
stack = []
userWeights.reverse_each {|item|
item.each {|key,value|
rec = {
'$cond' => [
{ '$eq' => [ '$user_id', key ] },
value
]
}
if ( stack.length == 0 )
rec['$cond'].push( 0 )
else
last = stack.pop
rec['$cond'].push( last )
end
stack.push( rec )
}
}
pipeline = [
{ '$project' => {
'user_id' => 1,
'content' => 1,
'date' => 1,
'weight' => stack[0]
}},
{ '$sort' => { 'weight' => -1, 'date' => -1 } }
]
puts JSON.pretty_generate( pipeline )
这是一种生成要传递到聚合的结构的方法,以便应用特定于user_id
的“权重”并对结果进行排序。
答案 1 :(得分:2)
首先感谢Neil对此here的帮助,这对我来说很有用,而且速度非常快。对于那些使用mongoid的人来说,这就是我用来创建weight_user_ids是数组的权重参数:
def self.project_recommended_weight recommended_user_ids
return {} unless recommended_user_ids.present?
{:weight => create_weight_statement(recommended_user_ids.reverse)}
end
def self.create_weight_statement recommended_user_ids, index=0
return 0 if index == recommended_user_ids.count
{"$cond" => [{ "$eq" => ["$user_id", recommended_user_ids[index]] },index+1,create_weight_statement(recommended_user_ids,index+1)]}
end
因此,要将此添加到管道,只需合并这样的哈希:
{"$project" => {:id => 1,:posted_at => 1}.merge(project_recommended_weight(options[:recommended_user_ids]))}