有没有更好的方法在JavaScript中对数组项进行部分求和?
我想知道是否有更好的方法为数组的部分和生成性能更好的解 给定一个数组,比如说有没有更好的方法在JavaScript中对数组项进行部分求和?,javascript,arrays,functional-programming,prefix-sum,Javascript,Arrays,Functional Programming,Prefix Sum,我想知道是否有更好的方法为数组的部分和生成性能更好的解 给定一个数组,比如说x=[0,1,2,3,4,5],我生成项目的子数组,然后计算每个数组的总和,得到: [ 0, 1, 3, 6, 10, 15 ] 因此,完整的代码是: x.map((y,i)=>x.filter((t,j)=>j<=i)) .map(ii=>ii.reduce((x,y)=>x+y,0)) x.map((y,i)=>x.filter((t,j)=>jii.reduce((x,y)=>x
x=[0,1,2,3,4,5]
,我生成项目的子数组,然后计算每个数组的总和,得到:
[ 0, 1, 3, 6, 10, 15 ]
因此,完整的代码是:
x.map((y,i)=>x.filter((t,j)=>j<=i))
.map(ii=>ii.reduce((x,y)=>x+y,0))
x.map((y,i)=>x.filter((t,j)=>jii.reduce((x,y)=>x+y,0))
我想知道flat map或其他一些数组方法是否有一个不需要扩展每个子数组的解决方案。一个选项是使用单个
.map
,它使用.reduce
来汇总切片的部分数组:
constx=[0,1,2,3,4,5];
常数和=(x,y)=>x+y;
const partialSums=x.map((u,i,arr)=>arr.slice(0,i+1).reduce(sum));
console.log(partialSums);
很多,通过保持一个运行总数:
函数*partialSums(可编辑){
设s=0;
for(iterable的常数x){
s+=x;
产量;
}
}
常数x=[0,1,2,3,4,5];
console.log(Array.from(partialSums(x)).join(“,”);
下面,scan
使用映射函数f
和初始累加器r
-
const scan=(f,r,[x,…xs])=>
x==未定义
?[r]
:[r,…扫描(f,f(r,x),xs)]
常数加=(x,y)=>
x+y
常量打印=(…vs)=>
vs.forEach(v=>console.log(v))
常量数据=
[ 0, 1, 2, 3, 4, 5 ]
打印
(扫描(添加、0、数据)
,扫描(Math.max,3,数据)
,扫描(添加,0,[])
)
// [ 0, 0, 1, 3, 6, 10, 15 ]
// [ 3, 3, 3, 3, 3, 4, 5 ]
//[0]
您可以简单地使用带有变量的for
循环来跟踪最后一次求和
设x=[0,1,2,3,4,5]
设总和=(arr)=>{
设和=0
让final=[]
对于(设i=0;i),平面图在您的情况下不会有用,因为您不会试图将部分结果作为列表进行展平,但我们可能会尝试在一个简化中解决您的问题:
它还只对数组进行一次迭代,因此与创建切片然后求和的解决方案相比,它的性能可能要高一些
或具有阵列的版本。推送,该版本重用相同的阵列:
[0, 1, 2, 3, 4, 5]
.reduce(
([arr, sum], el) => { // We pass along array and running sum
const next = sum + el
arr.push(next)
return [arr, next]
},
[[], 0] // We need to seed our reduce with empty array and accumulator for calculating running sum
)[0]
您只需要在每个步骤中将当前值添加到先前的结果中,这样就可以使用简单的reduce
常量数组=[0,1,2,3,4,5,6];
const sums=数组。reduce((acc、current、index)=>{
const prev=附件长度?附件[索引-1]:0;
acc.push(上一个+当前);
返回acc;
},[]);
console.log(sums.toString());
如果您询问是否有更快或更有效的方法,那么其他答案就足够了
然而,我认为,如果我们将它表述为一个映射函数,那么类似于当前解决方案的内容更容易阅读,更具声明性
var array = [ 0, 1, 2, 3, 4, 5 ];
function sumArray(arrayToSum, index){
if(index < arrayToSum.length-1){
arrayToSum[index+1] = arrayToSum[index] + arrayToSum[index+1];
return sumArray(arrayToSum, index+1);
}else
return arrayToSum;
}
sumArray(array, 0);
console.log(array);
特别是像“将每个值映射到自身加上数组中以前的所有值”
你可以使用一个过滤器,就像你在问题中所做的那样,但我认为一个片段更清晰
const x = [ 0, 1, 2, 3, 4, 5 ];
// A common generic helper function
const sum = (acc, val) => acc + val
const sums = x.map((val, i, self) => val + self.slice(0, i).reduce(sum, 0))
下面是一个使用递归函数的简单答案
var array = [ 0, 1, 2, 3, 4, 5 ];
function sumArray(arrayToSum, index){
if(index < arrayToSum.length-1){
arrayToSum[index+1] = arrayToSum[index] + arrayToSum[index+1];
return sumArray(arrayToSum, index+1);
}else
return arrayToSum;
}
sumArray(array, 0);
console.log(array);
var数组=[0,1,2,3,4,5];
函数sumArray(arrayToSum,索引){
if(索引
一种方法是对每个数组使用,然后对数组进行切片,以逐个获取元素,然后通过数组对所有元素求和。reduce
您可以这样做
设x=[0,1,2,3,4,5]
让sum=[]
x、 forEach((u,索引)=>{
索引++;
sum.push(x.slice(0,索引).reduce((a,b)=>a+b))
})
console.log(sum)
如果保留外部累加器变量,则可以直接使用map:
constx=[0,1,2,3,4,5];
设acc=0;
const prefixSum=x.map(x=>acc+=x);
log(前缀);
最简单的答案是一行:如果x是[0,1,2,3,4,5]
x.map(i=>s+=i, s=0)
顺便说一句,这称为前缀和或扫描。许多集合框架在标准库中都有它,但不幸的是ECMAScript没有。呃…yield
是一个很弱的词。将每个项添加到数组中,然后像人一样返回它。return
。@LogicalBranch:这不会在线,所以您最好使用第二个代码段嗯。@LogicalBranch为什么?迭代器FTW在2019年,不是吗?@LogicalBranch迭代器是做部分和的方法,如果你有一个大数组,或者你只需要一个特定的值。为什么你不喜欢收益率?我知道它不像return那样出现在你的脸上,但它描述了它在做什么。这是一个很好的命令式答案,但是,它没有这是一个带有函数式编程的问题。这只是一个特定辅助函数对一个非常特定的问题的1:1分配。零泛化,没有学到任何东西。这将同样缓慢(O(n²))因为它每次想添加一些东西时都会复制数组。@Ry-你可以很容易地用push
替换它,但它会变异数组,这会使它不完全起作用。你有没有看过有问题的tag函数式编程
?没有什么是完全起作用的。你拥有数组。这完全没问题。@Ry-不是真的ly,您可以使用纯函数方法。但是正如您所提到的,使用push
的版本在引用上是透明的,所以也可以。编辑我的答案以包含第二个版本。第二个代码片段看起来非常熟悉,甚至隐藏了。@Ry-上面的行说明您也可以使用map
,我想展示的是传统和实用的方法,如果人们觉得这是否决投票的正当理由,我很高兴:)scan
很好。在JavaScript中像Haskell一样实现scan
是不好的,因为它会给您带来二次时间复杂度和数组上的堆栈溢出,而这些数组甚至不是特别复杂