使用javascript嵌套分组(ES5)

时间:2018-02-28 15:53:52

标签: javascript ecmascript-5

我有一个对象数组如下:

(line < 0) and (test == 1)

我希望按( [ {"id":1,"lib":"A","categoryID":10,"categoryTitle":"Cat10","moduleID":"2","moduleTitle":"Module 2"}, {"id":2,"lib":"B","categoryID":10,"categoryTitle":"Cat10","moduleID":"2","moduleTitle":"Module 2"}, ... {"id":110,"lib":"XXX","categoryID":90,"categoryTitle":"Cat90","moduleID":"4","moduleTitle":"Module 4"} ] moduleID)然后按(moduleTitlecategoryID)对此数组进行分组。

这就是我的尝试:

categoryTitle

上面的代码按预期工作,但正如您所看到的,在第一次分组之后,我不得不再次遍历由function groupBy(data, id, text) { return data.reduce(function (rv, x) { var el = rv.find(function(r){ return r && r.id === x[id]; }); if (el) { el.children.push(x); } else { rv.push({ id: x[id], text: x[text], children: [x] }); } return rv; }, []); } var result = groupBy(response, "moduleID", "moduleTitle"); result.forEach(function(el){ el.children = groupBy(el.children, "categoryID", "categoryTitle"); }); 分组的数组,以便按moduleId进行分组

如何修改此代码,以便我只能在阵列上调用categoryId函数一次?

编辑:

对不起,这可能会迟到,但我想通过使用ES5,没有Shim和没有Polyfill来完成这项工作。

3 个答案:

答案 0 :(得分:2)

这是一种可能的(尽管可能有点高级)方法:

class DefaultMap extends Map {
    constructor(factory, iter) {
        super(iter || []);
        this.factory = factory;
    }

    get(key) {
        if (!this.has(key))
            this.set(key, this.factory());
        return super.get(key);
    }
}

基本上,它是一个Map,它在缺少值时调用工厂函数。现在,有趣的部分:

let grouper = new DefaultMap(() => new DefaultMap(Array));

for (let item of yourArray) {
    let firstKey = item.whatever;
    let secondKey = item.somethingElse;
    grouper.get(firstKey).get(secondKey).push(item);
}

对于每个firstKey,这会在Map内创建grouper,这些地图的值是按第二个键分组的数组。

你问题的一个更有趣的部分是你正在使用复合键,这在JS中非常棘手,因为它提供(几乎)不可变的数据结构。考虑:

items = [
    {a: 'one', b: 1},
    {a: 'one', b: 1},
    {a: 'one', b: 2},
    {a: 'two', b: 2},
]

let grouper = new DefaultMap(Array);

for (let x of items) {
    let key = [x.a, x.b];      // wrong!
    grouper.get(key).push(x);
}

因此,我们通过复合键天真地对对象进行分组,并希望在我们的石斑鱼中看到['one', 1]下的两个对象(为了示例,这是一个级别)。当然,这不起作用,因为每个key都是一个新创建的数组,并且Map或任何其他键控存储都有所不同。

一种可能的解决方案是为每个密钥创建一个不可变结构。一个明显的选择是使用Symbol,例如

let tuple = (...args) => Symbol.for(JSON.stringify(args))

然后

for (let x of items) {
    let key = tuple(x.a, x.b);      // works
    grouper.get(key).push(x);
}

答案 1 :(得分:1)

你可以这样做:

  const grouped = groupBy(response, "moduleID", "moduleTitle");

 console.log( grouped[2]["workflow"][exit] );

所以你可以像访问它一样访问它:

class EnergyModel:
     __init__(self):
          # set breakpoint
          import pdb; pdb.set_trace()
          ...

您可以放弃退出符号,但将嵌套树与数组混合会感觉有点不对。

答案 2 :(得分:1)

您可以使用数组作为分组ID /名称来扩展您的功能。

&#13;
&#13;
function groupBy(data, groups) {
    return data.reduce(function (rv, x) {
        groups.reduce(function (level, key) {
            var el;

            level.some(function (r) {
                if (r && r.id === x[key[0]]) {
                    el = r;
                    return true;
                }
            });
            if (!el) {
                el = { id: x[key[0]], text: x[key[1]], children: [] };
                level.push(el);
            }
            return el.children;
        }, rv).push({ id: x.id, text: x.lib });
        return rv;
    }, []);
}

var response = [{ id: 1, lib: "A", categoryID: 10, categoryTitle: "Cat10", moduleID: "2", moduleTitle: "Workflow" }, { id: 2, lib: "B", categoryID: 10, categoryTitle: "Cat10", moduleID: "2", moduleTitle: "Module 2" }, { id: 110, lib: "XXX", categoryID: 90, categoryTitle: "Cat90", moduleID: "4", moduleTitle: "Module 4" }],
    result = groupBy(response, [["moduleID", "moduleTitle"], ["categoryID", "categoryTitle"]]);

console.log(result);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

路径为id的版本。

&#13;
&#13;
function groupBy(data, groups) {
    return data.reduce(function (rv, x) {
        var path = [];
        var last = groups.reduce(function (level, key, i) {
            path.length = i;
            path[i] = key[0].slice(0, -2).toUpperCase() + ':' + x[key[0]];

            var id = path.join(';'),
                el = level.find(function (r) {
                    return r && r.id === id;
                });

            if (!el) {
                el = { id: path.join(';'), text: x[key[1]], children: [] };
                level.push(el);
            }
            return el.children;
        }, rv);

        last.push({ id: path.concat('NODE:' + x.id).join(';') });
        return rv;
    }, []);
}

var response = [{ id: 1, lib: "A", categoryID: 10, categoryTitle: "Cat10", moduleID: "2", moduleTitle: "Workflow" }, { id: 2, lib: "B", categoryID: 10, categoryTitle: "Cat10", moduleID: "2", moduleTitle: "Module 2" }, { id: 110, lib: "XXX", categoryID: 90, categoryTitle: "Cat90", moduleID: "4", moduleTitle: "Module 4" }];

    var result = groupBy(response, [["moduleID", "moduleTitle"], ["categoryID", "categoryTitle"]]);
console.log(result);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;