合并具有交替值的两个数组

时间:2017-11-01 18:10:41

标签: javascript ecmascript-6 functional-programming

我想合并两个不同长度的数组:

let array2 = ["a", "b", "c", "d"];
let array2 = [1, 2];

let outcome = ["a",1 ,"b", 2, "c", "d"] 

最好的办法是什么?

编辑:我期望的结果是["a", 1 ,"b", 2, "c", "d"]

13 个答案:

答案 0 :(得分:8)

这是使用解构赋值的另一种方法 -

const interleave = ([ x, ...xs ], ys = []) =>
  x === undefined
    ? ys                             // base: no x
    : [ x, ...interleave (ys, xs) ]  // inductive: some x
        
console.log (interleave ([0, 2, 4, 6], [1, 3, 5])) // [ 0 1 2 3 4 5 6 ]    
console.log (interleave ([0, 2, 4], [1, 3, 5, 7])) // [ 0 1 2 3 4 5 7 ]
console.log (interleave ([0, 2, 4], []))           // [ 0 2 4 ]
console.log (interleave ([], [1, 3, 5, 7]))        // [ 1 3 5 7 ]
console.log (interleave ([], []))                  // [ ]

另一种支持任意数量输入数组的变体 -

const interleave = ([ x, ...xs ], ...rest) =>
  x === undefined
    ? rest.length === 0
      ? []                               // base: no x, no rest
      : interleave (...rest)             // inductive: no x, some rest
    : [ x, ...interleave(...rest, xs) ]  // inductive: some x, some rest

console.log (interleave ([0, 2, 4, 6], [1, 3, 5])) // [ 0 1 2 3 4 5 6 ]    
console.log (interleave ([0, 2, 4], [1, 3, 5, 7])) // [ 0 1 2 3 4 5 7 ]
console.log (interleave ([0, 2, 4], []))           // [ 0 2 4 ]
console.log (interleave ([], [1, 3, 5, 7]))        // [ 1 3 5 7 ]
console.log (interleave ([], []))                  // [ ]

答案 1 :(得分:7)

您可以迭代两个数组的最小长度并构建替代元素,最后推动其余元素。

var array1 = ["a", "b", "c", "d"],
    array2 = [1, 2],
    result = [],
    i, l = Math.min(array1.length, array2.length);
    
for (i = 0; i < l; i++) {
    result.push(array1[i], array2[i]);
}
result.push(...array1.slice(l), ...array2.slice(l));

console.log(result);

使用转置算法和随后展平的任意数组数组的解决方案。

var array1 = ["a", "b", "c", "d"],
    array2 = [1, 2],
    result = [array1, array2]
        .reduce((r, a) => (a.forEach((a, i) => (r[i] = r[i] || []).push(a)), r), [])
        .reduce((a, b) => a.concat(b));
    
console.log(result);

答案 2 :(得分:6)

创建一个元组数组。每个元组包含每个数组中的1个元素,通过扩展元组数组展平,并从数组中添加剩余项:

const a1 = ["a", "b", "c", "d"];
const a2 = [1,2];
const l = Math.min(a1.length, a2.length);

const merged = [].concat(...Array.from({ length: l }, (_, i) => [a1[i], a2[i]]), a1.slice(l), a2.slice(l));
  
console.log(merged);

答案 3 :(得分:1)

这是一种现代解决方案,它可以使用任意数量的数组:

const braidArrays = (...arrays) => {
  const braided = [];
  for (let i = 0; i < Math.max(...arrays.map(a => a.length)); i++) {
    arrays.forEach((array) => {
      if (array[i] !== undefined) braided.push(array[i]);
    });
  }
  return braided;
};

请注意,您可以将Math.max更改为Math.min,以仅包含最短的数组。

这是一个示例I / O:

braidArrays(['a','b','c','d'], [1,2,3], [99,98,97,96,95]);
// ['a', 1, 99, 'b', 2, 98, 'c', 3, 97, 'd', 96, 95]

答案 4 :(得分:0)

ONELINER :我假设x=array1y=array2,x和y可以是任意arr

[...x,...y].reduce((l,c,i)=>(i<x.length&&l.push(x[i]),i<y.length&&l.push(y[i]),l),[])

工作example(适用于3种情况)

答案 5 :(得分:0)

您可以这样做:

const array1 = ["a", "b", "c", "d"];
const array2 = [1, 2];
const mergeArrays = (a, b) => (a.length > b.length ? a : b)
  .reduce((acc, cur, i) => a[i] && b[i] ? [...acc, a[i], b[i]] : [...acc, cur], []);

console.log(mergeArrays(array1, array2)); // ["a",1 ,"b", 2, "c", "d"]

答案 6 :(得分:0)

这可以使用match中的拼接功能来完成:

reduce

答案 7 :(得分:0)

有点冗长的解决方案,让您选择哪个数组排在最前面

const a = ['a', 'b', 'c'];
const b = [1, 4];
const combineAlternatingArrays = (a, b) => {
  let combined = [];
  const [shorter, larger] = [a, b].sort((a, b) => a.length -b.length);

  shorter.forEach((item, i) => {
    combined.push(larger[i], item);
  })
  combined.push(...larger.slice(shorter.length));

  return combined;
}
console.log(combineAlternatingArrays(a, b));

也可以使用reduce,但是在我看来,语法不太清楚。

const a = ['a', 'b', 'c'];
const b = [1, 4];
const combineAlternatingArrays = (a, b) => {
  const [shorter, larger] = [a, b].sort((a, b) => a.length -b.length);

  return shorter.reduce(
    (combined, next, i, shorter) => {
      return (i === (shorter.length -1)) ? [...combined, larger[i], next, ...larger.slice(shorter.length)] : [...combined, larger[i], next];
    },
    []
  );
}
console.log(combineAlternatingArrays(a, b));

答案 8 :(得分:0)

使用ES6 generator functions可以针对任何长度的任意数量的数组进行通用实现。关键是按顺序遍历所有数组,而不管其长度如何,然后将它们具有的每个值添加到单个合并数组中。

通过使用iterator protocol数组,我们可以统一遍历每个数组中的项目。

在生成其他序列的交替值的某个序列时,通常称为interleave。有时也称为Faro shuffle-在纸牌中更广为人知-完美的Faro随机播放结合了两堆纸牌,使得每堆纸牌交替出现。但是,这是一个交织序列的例子,数学家也使用该术语来描述交织过程。

//go through all arrays and produce their values
function* parallelWalkAllArrays(...arrays) {
  //get iterator for each array
  const iterators = arrays.map(arr => arr[Symbol.iterator]());
  
  let values;
  
  //loop until complete
  while (true) {
    values = iterators
      .map(it => it.next())      //addvance iterators
      .filter(({done}) => !done) //keep anything that is not finished
      .map(({value}) => value);  //get the values
      
    //quit if all are exhausted
    if (values.length === 0)
      return;
     
    //yield a tuple of all values
    yield values;
  }
}

function interleaveMergeArrays(...arrays) {
  //start a generator function
  const sequence = parallelWalkAllArrays(...arrays);
  
  let merged = [];
  //flatten each result into a single array
  for (const result of sequence) {
    merged.push(...result)
  }
  
  return merged;
}

const array1 = [1, 2, 3, 4, 5];
const array2 = ['a', 'b', 'c', 'd', 'e'];

console.log(
  interleaveMergeArrays(array1, array2)
);

const shortArray = ["apple", "banana"];

console.log(
  interleaveMergeArrays(array1, shortArray)
);
console.log(
  interleaveMergeArrays(shortArray, array2)
);
console.log(
  interleaveMergeArrays(array1, shortArray, array2)
);

或者,您可以采用非常相似的方法,但是直接从生成器生成平坦序列。这样,您可以立即食用它。

//go through all arrays and produce their values
function* walkAllArrays(...arrays) {
  //get iterator for each array
  const iterators = arrays.map(arr => arr[Symbol.iterator]());

  let values;

  //loop until complete
  while (true) {
    values = iterators
      .map(it => it.next())      //addvance iterators
      .filter(({done}) => !done) //keep anything that is not finished
      .map(({value}) => value);  //get the values

    //quit if all are exhausted
    if (values.length === 0)
      return;

    //yield each value
    for (const value of values) 
      yield value;
  }
}

const array1 = [1, 2, 3, 4, 5];
const array2 = ['a', 'b', 'c', 'd', 'e'];

console.log(Array.from(
  walkAllArrays(array1, array2)
));

const shortArray = ["apple", "banana"];

console.log(Array.from(
  walkAllArrays(array1, shortArray)
));
console.log(Array.from(
  walkAllArrays(shortArray, array2)
));
console.log(Array.from(
  walkAllArrays(array1, shortArray, array2)
));

我个人认为后一种方法不太灵活,因为它只能解决此问题。遍历所有数组的并行顺序遍历可以重新用于诸如压缩数组之类的其他事情,因此拥有辅助函数会消耗输出的输出,似乎可以使更多选项保持打开状态。另一方面,只有一个功能使查看它的实现方式更加简单。

答案 9 :(得分:0)

对于这种情况,我通常使用 nullish coalescing operator (??)

var mergeAlternately = (a, b) => {
  const maxLength = Math.max(a.length, b.length);
  let result = [];
  
  for (let i = 0; i < maxLength; i++) {
    result.push( (a[i] ?? '') , (b[i] ?? ''));
  } 
  // Remove empty array values
  return result.filter(item => item);
};

let array1 = ["a", "b", "c", "d"];
let array2 = [1, 2];

console.log(mergeAlternately(array1, array2))

答案 10 :(得分:0)

更现代、更高效、更短的方式:

const arr1 = ["a", "b", "c", "d"]
const arr2 = [1, 2]

const res = (arr1.length > arr2.length ? arr1 : arr2) // you can replace it with just arr1, if you know its always longer
            .flatMap((e, idx) => arr2[idx] ? [e, arr2[idx]] : [e])
console.log(res)

答案 11 :(得分:0)

使用迭代器:

function *gen(arr1, arr2){
    for(let i = 0; i < Math.max(arr1.length, arr2.length); i++) {
        if (arr1[i]) yield arr1[i];
        if (arr2[i]) yield arr2[i];
    }
}
const x = gen(['a','b','c','d'], [1,2]);
const result = [...x];

给予

Array(6) [ "a", 1, "b", 2, "c", "d" ]

答案 12 :(得分:0)

另一个ONELINER

const merge = (arr1, arr2) => ((arr1.length > arr2.length) ? arr1 : arr2).map((_,i)=>[arr1[i],arr2[i]]).flat().filter(Boolean);

说明:

  1. 用三元条件运算符取最长的数组
  2. 使用 map 为每个索引创建来自每个数组的一对元素
  3. 展平结果
  4. 删除未定义的