搜索对象数组(两个属性)以获取多个约束

时间:2018-10-26 10:15:06

标签: javascript arrays filter reduce

在我问这个问题之前,我为这个糟糕的标题表示歉意,但我无法更好地描述它。

我通过这种方式创建了一系列对象:

var setitems = new Array();
setitems.push({set: "1000", item: "5000"});
setitems.push({set: "1000", item: "5010"});
setitems.push({set: "1000", item: "5020"});
setitems.push({set: "1000", item: "5050"});
setitems.push({set: "1010", item: "5010"});
setitems.push({set: "1010", item: "5020"});
setitems.push({set: "1010", item: "5030"});
setitems.push({set: "1020", item: "5020"});
setitems.push({set: "1020", item: "5040"});
setitems.push({set: "1020", item: "5041"});
setitems.push({set: "1030", item: "5040"});
setitems.push({set: "1030", item: "5041"});
setitems.push({set: "1030", item: "5030"});
setitems.push({set: "1040", item: "5041"});
setitems.push({set: "1040", item: "5042"});

项目和集合之间存在多对多的关系。

还有一个像这样的简单字符串数组:

var itemlist = new Array();
itemlist.push("5010");
itemlist.push("5020");
// itemlist = ["5010", "5020"];

我需要知道哪些集合包含itemlist中的所有项目。

在此示例中,它应返回1000和1010。

每套物品的数量是可变的。

itemlist中的os项目数是可变的。

谢谢。

3 个答案:

答案 0 :(得分:1)

您可以先按集合对项目进行分组,然后检查某个集合是否包括itemList中的每个项目。希望这会有所帮助。

const setitems = [];
setitems.push({set: "1000", item: "5000"});
setitems.push({set: "1000", item: "5010"});
setitems.push({set: "1000", item: "5020"});
setitems.push({set: "1000", item: "5050"});
setitems.push({set: "1010", item: "5010"});
setitems.push({set: "1010", item: "5020"});
setitems.push({set: "1010", item: "5030"});
setitems.push({set: "1020", item: "5020"});
setitems.push({set: "1020", item: "5040"});
setitems.push({set: "1020", item: "5041"});
setitems.push({set: "1030", item: "5040"});
setitems.push({set: "1030", item: "5041"});
setitems.push({set: "1030", item: "5030"});
setitems.push({set: "1040", item: "5041"});
setitems.push({set: "1040", item: "5042"});

const itemlist = [];
itemlist.push("5010");
itemlist.push("5020");

const find = (arr, list) => {

    const grouped = arr.reduce((acc, val) => ({ ...acc, [val.set]: (acc[val.set] || []).concat(val.item) }), {});

    return Object.keys(grouped).reduce((acc, val) => {
        
        if (list.every(item => grouped[val].includes(item))) acc.push(val);
        
        return acc;
        
    }, []);
};

console.log(find(setitems, itemlist));

答案 1 :(得分:1)

您可以使用Set个实例:

// Get an array of Set instances for entries matching itemlist entries
const [first, ...rest] = itemlist.map(item =>
    setitems.filter(entry => entry.item === item)
            .reduce((s, entry) => s.add(entry.set), new Set())
);
// Get an array of the entries in the first of those Sets that also have entries in all the rest
const result = [...first].filter(set => rest.every(s => s.has(set)));

const setitems = [];
setitems.push({set: "1000", item: "5000"});
setitems.push({set: "1000", item: "5010"});
setitems.push({set: "1000", item: "5020"});
setitems.push({set: "1000", item: "5050"});
setitems.push({set: "1010", item: "5010"});
setitems.push({set: "1010", item: "5020"});
setitems.push({set: "1010", item: "5030"});
setitems.push({set: "1020", item: "5020"});
setitems.push({set: "1020", item: "5040"});
setitems.push({set: "1020", item: "5041"});
setitems.push({set: "1030", item: "5040"});
setitems.push({set: "1030", item: "5041"});
setitems.push({set: "1030", item: "5030"});
setitems.push({set: "1040", item: "5041"});
setitems.push({set: "1040", item: "5042"});

const itemlist = [];
itemlist.push("5010");
itemlist.push("5020");

// Get an array of Set instances for entries matching itemlist entries
const [first, ...rest] = itemlist.map(item =>
    setitems.filter(entry => entry.item === item)
            .reduce((s, entry) => s.add(entry.set), new Set())
);
// Get an array of the entries in the first of those Sets that also have entries in all the rest
const result = [...first].filter(set => rest.every(s => s.has(set)));
console.log(result);

答案 2 :(得分:1)

可能的解决方案可能使用两步法。

第一步,创建所有可能的“设置”值列表的地图/表格/注册表。

最后一步产生结果。它创建一个“集合”标识符列表,其中每个相关的“集合”值列表都包含另一个提供的值列表的每个值。

那么只有ES5的代码可能看起来像这样...

var setItemList = new Array();
setItemList.push({set: "1000", item: "5000"});
setItemList.push({set: "1000", item: "5010"});
setItemList.push({set: "1000", item: "5020"});
setItemList.push({set: "1000", item: "5050"});
setItemList.push({set: "1010", item: "5010"});
setItemList.push({set: "1010", item: "5020"});
setItemList.push({set: "1010", item: "5030"});
setItemList.push({set: "1020", item: "5020"});
setItemList.push({set: "1020", item: "5040"});
setItemList.push({set: "1020", item: "5041"});
setItemList.push({set: "1030", item: "5040"});
setItemList.push({set: "1030", item: "5041"});
setItemList.push({set: "1030", item: "5030"});
setItemList.push({set: "1040", item: "5041"});
setItemList.push({set: "1040", item: "5042"});

var itemlist = new Array();
itemlist.push("5010");
itemlist.push("5020");


// ... with good old ES-5 do ...


// 1st part of solution ... create a map/table/registry of all possible "set" value lists.
//
function collectAndFillSetValueLists (registry, setItem) {
    var key   = setItem.set;
    var value = setItem.item;
    var list  = registry[key] || (registry[key] = []); // get or create a "set" item specific list.

    // if (!list.includes(value)) {
    if (list.indexOf(value) === -1) {

        list.push(value);
    }
    return registry;
}
var setItemsRegistry = setItemList.reduce(collectAndFillSetValueLists, {});

console.log('setItemsRegistry : ', setItemsRegistry);


// 2nd part of solution ... create a list of "set" identifiers where each related
// "set" value list contains every value of another provided value list.
//
function collectSetIdsThatsListsContainEveryValue(collector, setKey) {
    var list = collector.registry[setKey];
    if (collector.valueList.every(function (setValue) {

        return (list.indexOf(setValue) >= 0);
        // return list.includes(setValue);
    })) {
        collector.keyList.push(setKey)
    }
    return collector;
}
var setIdentifierList = Object.keys(setItemsRegistry).reduce(collectSetIdsThatsListsContainEveryValue, {

    registry: setItemsRegistry,
    valueList: itemlist,
    keyList: []

}).keyList;

console.log('setIdentifierList : ', setIdentifierList);
.as-console-wrapper { max-height: 100%!important; top: 0; }