如何高效地解压数组

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

How to deflat an array efficiently

问题

我需要频繁地对数组进行扁平化和还原。因此,我使用了常规的方式,使用reduce函数来解决这个问题,如下所示:

let arr = [[1,2], [3,4]] 
let flatendarr = arr.flat(2)
console.log("扁平化", flatendarr)

let deflatarr =  flatendarr.reduce((pv, cv) => {
     pv.temp.push(cv)    
     if(pv.temp.length == 2) {
          pv.res.push(pv.temp)
          pv.temp = []
     }
     return pv
}, {res: [], temp: []})

console.log("还原",deflatarr.res)

由于我需要多次运行这段代码,可能会运行500到1000次,我担心效率的问题。

对于大型数据,我遇到了1到2秒的延迟,我在寻找是否有更高效的方法。

英文:

I have a requirement where I need to flat and deflat an array frequently. So, I solved that with usual way using reduce function like below

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

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

let arr = [[1,2], [3,4]] 
let flatendarr = arr.flat(2)
console.log(&quot;flat&quot;, flatendarr)

let deflatarr =  flatendarr.reduce((pv, cv) =&gt; {
     pv.temp.push(cv)    
     if(pv.temp.length == 2) {
          pv.res.push(pv.temp)
          pv.temp = []
     }
     return pv
}, {res: [], temp: []})

console.log(&quot;de-flat&quot;,deflatarr.res)

<!-- end snippet -->

Since I need to run this code several times may be 500 to 1000 times I'm concerning about efficiency.

Since for large data I'm facing a delay of 1 to 2 seconds I'm searching Is there any other approach which is more efficient.

答案1

得分: 1

不要进行推动和减少

这不会有良好的性能。

我假设您确实需要解开嵌套,因为您在实际情况下不会从解开的数组开始,所以不会有简单地保留它的选项。

尝试标准循环

  • 创建一个长度正确的解开后的输出数组
  • 循环遍历此输出数组的元素,将来自解开后的数组的相关值数组插入到每个条目中

您似乎热衷于使用_函数式_方法:如果是这样,请尝试.map

速度最好在大型数据集上进行测试

在这个数据集上尝试进行速度比较:

英文:

Don't do pushing and reduce

That is not going to be performant.

I assume that you genuinely need to de-flatten, because you won't in practice be starting with the de-flattened array and so won't have the option to simply retain it.

Try a standard loop

  • Create an array for the de-flattened output, of the correct length
  • Loop over the elements of this output array, inserting into each entry the array of relevant values from the flattened array

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

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

let arr = [
  [1, 2],
  [3, 4]
]
let flatendarr = arr.flat(2)
console.log(&quot;flat&quot;, flatendarr)

const deflatarr = Array(Math.floor(flatendarr.length/2 ))
for (let i = 0; i &lt; flatendarr.length/2; i ++) {
  deflatarr[i] = [flatendarr[2 * i], flatendarr[2 * i + 1]]
}

console.log(&quot;de-flat&quot;, deflatarr)

<!-- end snippet -->

You seem keen on a functional approach: if so, try .map

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

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

let arr = [
  [1, 2],
  [3, 4]
]
let flatendarr = arr.flat(2)
console.log(&quot;flat&quot;, flatendarr)

const deflatarr = Array(Math.floor(flatendarr.length / 2)).fill(0).map(
  (dummy, i) =&gt; [flatendarr[2 * i], flatendarr[2 * i + 1]]
)
console.log(&quot;de-flat&quot;, deflatarr)

<!-- end snippet -->

Speed is best tested on large datasets

Try your speed comparison on this dataset:

let flatendarr = Array(50000).fill(0).map((dummy,i)=&gt;1+i)

const deflatarr = Array((flatendarr.length / 2)).map(
  (dummy, i) =&gt; [flatendarr[2 * i], flatendarr[2 * i + 1]]
)
console.log(&quot;de-flat&quot;, deflatarr)

答案2

得分: 1

另一种方法是不要将数组展平,而是为期望它为平的逻辑部分提供实用函数。

以下是一些想法:

const flatAt = (arr, i) => arr[i >> 1][i & 1];
const flatPutAt = (arr, i, val) => arr[i >> 1][i & 1] = val;
const flatLength = (arr) => arr.length * 2;

function* flatValues(arr) {
    for (const pair of arr) yield* pair;
}

// 演示
let arr = [[1,2], [3,4]];

console.log("get");
for (let i = 0, size = flatLength(arr); i < size; i++) {
    console.log(flatAt(arr, i));
}
console.log("double");
for (let i = 0, size = flatLength(arr); i < size; i++) {
    console.log(flatPutAt(arr, i, flatAt(arr, i) * 2));
}
console.log("iter", ...flatValues(arr));

你还可以更进一步,创建一个类:

class ArrayAsFlat extends Array {
    flatAt(i) {
        return this[i >> 1][i & 1];
    }
    flatPutAt(i, val) {
        return this[i >> 1][i & 1] = val;
    }
    *flatValues() {
        for (const pair of this) yield* pair;
    }
    get flatLength() {
        return this.length * 2;
    }
}

// 演示
const arr = new ArrayAsFlat([1,2], [3,4]);

console.log("get");
for (let i = 0, size = arr.flatLength; i < size; i++) {
    console.log(arr.flatAt(i));
}
console.log("double");
for (let i = 0, size = arr.flatLength; i < size; i++) {
    console.log(arr.flatPutAt(i, arr.flatAt(i) * 2));
}
console.log("iter", ...arr.flatValues());

是否更高效取决于使用附加方法执行多少操作。如果你的大部分代码需要平坦类型的访问,那么你可以反过来,从一开始就将数组存储为平坦的,并提供方法,将值返回(或设置)为如果数组是嵌套的一样。

最佳解决方案是将代码转换为仅使用一种访问类型,以便不需要转换。

英文:

Another approach would be where you don't flatten the array, but provide utility functions for those parts of the logic that expects it to be flat.

Here are some ideas:

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

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

const flatAt = (arr, i) =&gt; arr[i &gt;&gt; 1][i &amp; 1];
const flatPutAt = (arr, i, val) =&gt; arr[i &gt;&gt; 1][i &amp; 1] = val;
const flatLength = (arr) =&gt; arr.length * 2;

function* flatValues(arr) {
    for (const pair of arr) yield* pair;
}

// Demo
let arr = [[1,2], [3,4]];

console.log(&quot;get&quot;);
for (let i = 0, size = flatLength(arr); i &lt; size; i++) {
    console.log(flatAt(arr, i));
}
console.log(&quot;double&quot;);
for (let i = 0, size = flatLength(arr); i &lt; size; i++) {
    console.log(flatPutAt(arr, i, flatAt(arr, i) * 2));
}
console.log(&quot;iter&quot;, ...flatValues(arr));

<!-- end snippet -->

You could take it a step further and create a class for it:

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

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

class ArrayAsFlat extends Array {
    flatAt(i) {
        return this[i &gt;&gt; 1][i &amp; 1];
    }
    flatPutAt(i, val) {
        return this[i &gt;&gt; 1][i &amp; 1] = val;
    }
    *flatValues() {
        for (const pair of this) yield* pair;    
    }
    get flatLength() {
        return this.length * 2;
    }
}

// Demo
const arr = new ArrayAsFlat([1,2], [3,4]);

console.log(&quot;get&quot;);
for (let i = 0, size = arr.flatLength; i &lt; size; i++) {
    console.log(arr.flatAt(i));
}
console.log(&quot;double&quot;);
for (let i = 0, size = arr.flatLength; i &lt; size; i++) {
    console.log(arr.flatPutAt(i, arr.flatAt(i) * 2));
}
console.log(&quot;iter&quot;, ...arr.flatValues());

<!-- end snippet -->

Whether or not this turns out to be more efficient depends on how many actions you have to perform using the additional methods.

If most of your code needs the flat type of access, then you could do the inverse, and store the array as flat from the start and provide methods that will return (or set) values as if the array were nested.

The best solution would be to convert your code so it uses one type of access only, so no conversion is needed.

huangapple
  • 本文由 发表于 2023年3月9日 14:13:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75680998.html
匿名

发表评论

匿名网友

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

确定