2013-02-15 48 views
1

我有一個包含JSON對象數組如實現帶有JSON陣列交叉值

validTags = [{"tag":"tag1"}, {"tag":"tag2"}]; 

items = [{"id":123456, "tag":"tag1"}, {"id":123456, "tag":"tag2"}, {"id":7890, "tag":"tag1"}]; 

,我試圖找出的ID的同時具有「標籤」從第一個數組開始。

E.g.輸出將是:

[{"id":123456, "tag":"tag1 tag2"}] 

將兩個匹配標籤組合成一個字符串。

任何想法我應該如何去做這件事?我正在和Javascript聊天室中的一些SO用戶聊天,他們建議可以使用數組交叉口,但我不完全確定如何使用這個來獲得JSON的預期結果:(

全部答案/幫助表示讚賞

非常感謝

+0

的'tag1'和'tag2'變量字符串? – Bergi 2013-02-15 15:20:25

+0

哎呀,是的,已編輯,以反映這一點! – Mac 2013-02-15 15:21:44

回答

1

下面是使用對象和數組的溶液:

validTags = [{"tag":"tag1"}, {"tag":"tag2"}]; 
items = [{"id":123456, "tag":"tag1"}, {"id":123456, "tag":"tag2"}, {"id":7890, "tag":"tag1"}]; 

accumulate = {}; 
// Make use of the hashing of JavaScript objects to merge the tags. 
items.forEach(function(e) { 
    if(accumulate[e.id] == undefined) accumulate[e.id] = [e.tag]; 
    else accumulate[e.id].push(e.tag); 
}); 

// Convert the object into an array. The field 'tags' is still an array. 
var result0 = []; 
for(var id in accumulate) result0.push({"id": id, tags: accumulate[id]}); 

var result = result0.filter(
    // First we cross out those do not contain every tag. 
    function(e) { return validTags.every(
    function(e1) { return e.tags.indexOf(e1.tag) != -1; }); }) 
    // Then we make the 'tags' array into a string. 
    .map(function(e) { return {"id": e.id, "tags": e.tags.join(" ")}; }); 
+0

完美運作。解釋基本步驟的評論也很棒!謝謝 – Mac 2013-02-15 16:13:42

1

這應該這樣做:

var validTags = [{"tag":"tag1"}, {"tag":"tag2"}]; 
var items = [{"id":123456, "tag":"tag1"}, {"id":123456, "tag":"tag2"}, {"id":7890, "tag":"tag1"}]; 

var actualTags = validTags.map(function(obj){return obj.tag}), 
    comparableTags = actualTags.sort().join(" "); 

var tagsById = items.reduce(function(map, item) { 
    if (item.id in map) 
     map[item.id].push(item.tag); 
    else 
     map[item.id] = [ item.tag ]; 
    return map; 
}, {}); 
var result = []; 
for (var id in tagsById) { 
    var tags = tagsById[id].sort().join(" "); 
    if (comparableTags == tags) // Yai, array comparison by content! 
     result.push({id: id, tag:tags}); 
} 
return result; 

如果您正在使用Underscore,你可以使用pluck代替mapgroupBy而不是reduce;總之:

var comparableTags = _.pluck(validTags, "tag").sort().join(" "); 
return _.chain(items).groupBy("id").map(function(id, tags) { 
    return {id:id, tag:tags.sort().join(" "); 
}.filter(function(obj) { 
    return obj.tag == comparableTags; 
}).value(); 
+0

阿好吧brill(我正在使用下劃線:D)。有了上面的代碼,如果我有var validTags = [{「tag」:「tag1」}];是否有可能返回包含tag1的項目,即使它們也包含tag2?所以目前如果它只是在有效標籤中的「tag1」,我會返回ID 7890,但是我也可以返回ID 123456(因爲它的tag1已分配給它)? – Mac 2013-02-15 15:37:00

+0

然後不要使用我的字符串比較,但像'if(_difference(actualTags,obj.tags).length == 0)'(其中'obj.tags'仍然是一個數組)。不知道是否有更具表現力和高性能的方式 – Bergi 2013-02-15 15:39:53

+0

感謝您的幫助 – Mac 2013-02-15 16:18:22

3

有在JavaScript中沒有固定的操作,但是他們很容易界定,例如:

intersection = function(a, b) { 
    return a.filter(function(x) { return b.indexOf(x) >= 0 }) 
} 

針對您的特殊任務,首先轉換validTags到一個列表:

vtags = validTags.map(function(x) { return x.tag }) 

然後計算一個十字路口,將items中的每個tag屬性轉換爲一個數組:

results = items.filter(function(x) { 
    return intersection(x.tag.split(/\s+/), vtags).length == vtags.length 
}) 
+0

感謝您的解釋 – Mac 2013-02-15 16:17:44