嵌套分区数据结构 JavaScript

huangapple go评论64阅读模式
英文:

Nested partition data structure JavaScript

问题

我正在尝试找出适用于我的用例的最佳数据结构/类。

我有几个数组(都是长度为 n ),我想要使用它们创建一个分区。我希望能够至少嵌套分区一层(从示例中应该清楚)。我还希望能够使用类似 reduce 的函数来汇总一些其他数组的值(也都是长度为 n ),既在内部(嵌套)分区,又在外部(非嵌套)分区。

我在考虑一个类似这样的 API:

const arr1 = [1, 0, 0, 1, 1, 0, 0, 1];
const arr2 = ["A", "A", "A", "B", "C", "B", "B", "A"];
const arr3 = [100, 250, 100, 300, 150, 250, 300, 150];

const partition = Partition.from(arr2)
  .nest(arr1)
  .reduceWith({arr3}, (a, b) => a + b, 0);

partition.outer() // { "A": { arr3: 600 }, "B": { arr3: 850 }, "C": { arr3: 150 } }
partition.inner() // { "A0": { arr3: 350 }, "A1" : { arr3: 250 }, "B0": { arr3: 550 }, "B1": { arr3: 300 }, "C1": { arr3: 150 } }

// ^^我使用了类似 "A0","B1" 等字符串作为键,以使事情更清晰一些,
// 但在实际使用中,我可能会使用 JSON 字符串,例如 "{ "arr2":"B","arr1":0}",
// 以使分区 ID 不那么模糊不清。

重要的是,嵌套数组的具体值(但不是长度或唯一值)会随时间变化,因此数据结构需要允许反应性(我正在使用 Solid JS)。内部分区可能更经常更改,它们只应在必要时重新计算。

有人有任何想法或了解一个好的模式吗?

英文:

I'm trying to figure out what would be the best data structure/class for my use case.

I have several arrays (all of length n) that I want to use to create a partition. I want to be able to nest the partition at least one layer deep (hopefully will be clear from the example). I also want to be able to summarize the values of some other arrays (also of length n) with a reduce-like function, both within the inner (nested) and the outer (non-nested) partitions.

I'm thinking an API like this:

const arr1 = [1, 0, 0, 1, 1, 0, 0, 1];
const arr2 = ["A", "A", "A", "B", "C", "B", "B", "A"];
const arr3 = [100, 250, 100, 300, 150, 250, 300, 150];

const partition = Partition.from(arr2)
  .nest(arr1)
  .reduceWith({arr3}, (a, b) => a + b, 0);

partition.outer() // { "A": { arr3: 600 }, "B": { arr3: 850 }, "C": { arr3: 150 } }
partition.inner() // { "A0": { arr3: 350 }, "A1" : { arr3: 250 }, "B0": { arr3: 550 }, "B1": { arr3: 300 }, "C1": { arr3: 150 } }
  

// ^^I used strings like "A0", "B1" etc..., as keys to make things a bit clearer,
// but in practice I might use JSON strings, e.g. "{"arr2":"B","arr1":0}", 
// to make the partition ids less ambiguous

Importantly, the specific values (but not the length or unique values) of the nesting arrays will change over time, so the data structure needs to allow for reactivity (I am using Solid JS). The inner partition might change more often than the outer one, and they should only be recomputed when necessary.

Anyone has any ideas/knows of a good pattern?

答案1

得分: 1

以下是您要翻译的代码部分:

class Partition {
    constructor() {
        this.levels = [];
        this.values = [];
    }
    addLevel(level) {
        this.levels.push(level);
        return this;
    }
    reduceWith(obj, reducer) {
        [this.key, this.values] = Object.entries(obj)[0];
        this.reducer = reducer;
        return this;
    }
    produce(level=1) {
        const levels = this.levels.slice(0, level);
        const {key} = this;
        return this.values.reduce((acc, value, i) => {
            const group = levels.map(level => level[i]).join("");
            if (group in acc) {
                acc[group][key] = this.reducer(acc[group][key], value);
            } else {
                acc[group] = { [key]: value };
            }
            return acc;
        }, {});
    }
}

const arr1 = [1, 0, 0, 1, 1, 0, 0, 1];
const arr2 = ["A", "A", "A", "B", "C", "B", "B", "A"];
const arr3 = [100, 250, 100, 300, 150, 250, 300, 150];

const partition = new Partition()
  .addLevel(arr2)
  .addLevel(arr1)
  .reduceWith({ arr3 }, (a, b) => a + b);

console.log(partition.produce(0)); // { "": { arr3: 1600 } }
console.log(partition.produce(1)); // { "A": { arr3: 600 }, "B": { arr3: 850 }, "C": { arr3: 150 } }
console.log(partition.produce(2)); // { "A0": { arr3: 350 }, "A1": { arr3: 250 }, "B0": { arr3: 550 }, "B1": { arr3: 300 }, "C1": { arr3: 150 } }
英文:

You could create a class Partition (which must be instanciated with new), and define a method addLevel (corresponding to both from and nest in your suggestion) which returns the instance again for chaining, and a method reduceWith which also returns the instance.

Then what you call outer and inner would be combined in a single method produce that takes a level as argument (like 1 for outer, and 2 for inner). This is more generic, and you could even generate a grand total (without partitioning) by passing level 0 as argument.

Here it is:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

class Partition {
constructor() {
this.levels = [];
this.values = [];
}
addLevel(level) {
this.levels.push(level);
return this;
}
reduceWith(obj, reducer) {
[this.key, this.values] = Object.entries(obj)[0];
this.reducer = reducer;
return this;
}
produce(level=1) {
const levels = this.levels.slice(0, level);
const {key} = this;
return this.values.reduce((acc, value, i) =&gt; {
const group = levels.map(level =&gt; level[i]).join(&quot;&quot;);
if (group in acc) {
acc[group][key] = this.reducer(acc[group][key], value);
} else {
acc[group] = {[key]: value};
}
return acc;
}, {});
}
}
const arr1 = [1, 0, 0, 1, 1, 0, 0, 1];
const arr2 = [&quot;A&quot;, &quot;A&quot;, &quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;B&quot;, &quot;B&quot;, &quot;A&quot;];
const arr3 = [100, 250, 100, 300, 150, 250, 300, 150];
const partition = new Partition()
.addLevel(arr2)
.addLevel(arr1)
.reduceWith({arr3}, (a, b) =&gt; a + b);
console.log(partition.produce(0)); // { &quot;&quot;: { arr3: 1600 } }
console.log(partition.produce(1)); // { &quot;A&quot;: { arr3: 600 }, &quot;B&quot;: { arr3: 850 }, &quot;C&quot;: { arr3: 150 } }
console.log(partition.produce(2)); // { &quot;A0&quot;: { arr3: 350 }, &quot;A1&quot; : { arr3: 250 }, &quot;B0&quot;: { arr3: 550 }, &quot;B1&quot;: { arr3: 300 }, &quot;C1&quot;: { arr3: 150 } }

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年3月7日 03:48:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75655216.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定