【问题标题】:What is the most elegant way to insert objects between array elements?在数组元素之间插入对象的最优雅的方法是什么?
【发布时间】:2015-08-07 14:00:18
【问题描述】:

我确信有很多方法可以实现这一目标,但我正在寻找“优雅”的东西。

a = [
  'a',
  'b',
  'c'
];

magicArrayJoin(a, {value: 255} ); // insert the same object between each item

result ==  [
  'a',
  {value: 255},
  'b',
  {value: 255}
  'c'
];

欢迎所有建议。 :)

【问题讨论】:

  • “magicArrayJoin”到底应该做什么?它是按某个固定间隔插入第二个参数,还是仅在每个项目之间插入第二个参数?
  • @Pointy 我不认为这是一个骗局。 OP 没有询问如何将元素插入到数组中的某个位置。他们在问如何将一个元素插入到每个元素之间的数组中。
  • @cimak 您是否在询问如何在数组中的所有元素之间(重复)插入 one 对象,如您的示例所示?或者您是在问如何在数组中的元素之间插入多个对象,如问题标题所示?另外,您是否需要修改数组或创建一个新数组?
  • 我想在每个项目之间插入相同的对象。修改现有数组或创建新数组 - 没关系。

标签: javascript arrays


【解决方案1】:

你可以用 flatMap 做到这一点。例如可以从lodash找到

_.flatMap([1,2,3,4], (value, index, array) =>
     array.length -1 !== index // check for the last item
     ? [value, "s"]
     : value
);

输出

[1, "s", 2, "s", 3, "s", 4]

更新

Array#flatMap proposal 正在开发中,因此将来应该可以使用:

[1, 2, 3, 4].flatMap(
    (value, index, array) =>
        array.length - 1 !== index // check for the last item
            ? [value, "s"]
            : value,
);

【讨论】:

  • 有点惊讶没有更有效的内置 lodash 函数
【解决方案2】:

使用纯 ES6 的单行代码:

const interleave = (arr, thing) => [].concat(...arr.map(n => [n, thing])).slice(0, -1)

用法:

interleave(['foo', 'bar', 'baz'], 'avocado')

打印:

> ["foo", "avocado", "bar", "avocado", "baz"]

【讨论】:

  • 不错的技术——现在可以是const interleave = (arr, x) => arr.flatMap(e => [e, x]).slice(0, -1)
【解决方案3】:

在我看来,最优雅的方法是:

ES6 语法版本

const insertIntoArray = (arr, value) => {

    return arr.reduce((result, element, index, array) => {

        result.push(element);

        if (index < array.length - 1) {
            result.push(value);
        }

        return result;
    }, []);
};

用法:

insertIntoArray([1, 2, 3], 'x'); // => [1, 'x', 2, 'x', 3]

【讨论】:

  • 很明显,有一种非理性的偏见倾向于使用 reduce,因为它比两年前 Bergi 的完美和更有效的答案有更多的赞成票?
  • @Andy 这就是为什么最初的问题询问了一种优雅的方式来做到这一点?
  • 就优雅而不是性能而言,Bergi 的回答中的concatMap 示例对我来说似乎很优雅,但以这种方式使用reduce 则不然
【解决方案4】:

一个普通的循环似乎是最好的:

function intersperse(arr, el) {
    var res = [], i=0;
    if (i < arr.length)
        res.push(arr[i++]);
    while (i < arr.length)
        res.push(el, arr[i++]);
    return res;
}

如果您正在寻找优雅的东西,它可能必须使用某种concatMap,如

function concatMap(arr, fn) { return [].concat.apply([], arr.map(fn)); }
function intersperse(arr, el) { return concatMap(arr, x => [el, x]).slice(1); }

【讨论】:

    【解决方案5】:

    不可变的解决方案

    当减少一个数组时,reduce 函数不应该改变数组,而是返回一个新值(在这种情况下是一个新数组)。这样,更改将仅应用于返回的数组,而不是原始数组,并且将避免副作用。

    const insertBetween = (insertee, array) => array.reduce(
        (acc, item, i, { length }) => {
            if (i && i < length) {
                return [...acc, insertee, item];
            }
            return [...acc, item];
        },
        []
    );
    

    【讨论】:

    • 我认为这是在实例化大量中间数组。
    • 在支持尾调用优化的引擎中,您可以使用 LISPy 方式:(insertee, array) =&gt; array.length &lt;= 1 ? array : [array[0], insertee, ...insertBetween(insertee, array.slice(1))]
    【解决方案6】:

    Ramda 具有 intersperse 方法:

    创建一个新列表,在元素之间插入分隔符。

    代码:

    R.intersperse({name: 'separator'}, ['one', 'two', 'three']);
    

    结果:

    [
        'one',
        {name: 'separator'},
        'two',
        {name: 'separator'},
        'three'
    ]
    

    【讨论】:

      【解决方案7】:

      使用 ES6 flatMap 函数。

      const insertBetween = (ele, array) => {
        return array.flatMap((x) => [ele, x]).slice(1);
      };
      
      insertBetween('+', [1, 2, 3]);
      

      【讨论】:

        【解决方案8】:

        您可以使用 reduce 来实现这一点(它也是不可变的)。

        const insertBetween = (insertion, array) =>
            array.reduce(
                (newArray, member, i, array) =>
                    i < array.length - 1 
                        ? newArray.concat(member, insertion) 
                        : newArray.concat(member),
                []
            );
        
        const result = insertBetween('and', [1, 2, 3]);
        
        console.log(result);
        
        // outputs;
        // [
        //   1, 
        //   'and', 
        //   2, 
        //   'and', 
        //   3
        // ]

        或者在旧的 JS 语法中;

        function insertBetween(insertion, array) {
            const indexOfLastItem = array.length - 1;
            return array.reduce(withInsertion, []);
        
            function withInsertion(newArray, item, index, array) {
                return index < indexOfLastItem 
                    ? newArray.concat(item, insertion) 
                    : newArray.concat(item);
            }
        }
        
        const result = insertBetween('and', [1, 2, 3]);
        
        console.log(result);
        
        // outputs;
        // [
        //   1, 
        //   'and', 
        //   2, 
        //   'and', 
        //   3
        // ]

        【讨论】:

          【解决方案9】:

          我非常赞成@Vidul 的cmets,它非常符合逻辑和简洁!我自己也想出了splice(),但错过了%。然而,大多数牙套似乎没有必要作为单线。可以进一步简化为

          for (var i = 0; i < a.length; i++) if (i % 2) a.splice(i, 0, {value: 255});
          

          【讨论】:

            【解决方案10】:
            function insertObject(arr, obj) {
              var result = [];
            
              function insert(element, index) {
                result.push(element);
                if (index + 1 < arr.length) {
                  result.push(obj);
                }
              }
              arr.forEach(insert);
              return result;
            }
            var a = [1, 2, 3, 4];
            insertObject(a, {
              test: 'test'
            });
            

            【讨论】:

              【解决方案11】:

              按照 Kamen 的建议使用拼接,您可以执行以下操作:

              const numSeparators = arr.length - 1;
              for (let i = 1; i <= numSeparators; i++) {
                  const index = (i * 2) - 1;
                  arr.splice(index, 0, { value: 255 });
              }
              

              【讨论】:

                【解决方案12】:

                对于一个简单的纯功能方式,我建议这样做:

                const magicArrayJoin = (array, el) =>
                  array.length ?
                    array.slice(1).reduce((acc, cur) => acc.concat([el, cur]), [array[0]]) :
                    []
                

                p.n.这种方式不是javascript中性能最高的一种

                【讨论】:

                • 你需要array.slice(1),否则array[0]会被插入两次
                【解决方案13】:

                ES6:

                const arrayWithSeparator = array.reduce((a, i) => a.length ? a.push(separator) && a.push(i) && a : a.push(u) && a, [])
                

                【讨论】:

                  【解决方案14】:

                  Array.splice() 应该这样做:

                  a.splice(1, 0, {value : 255})

                  第一个参数是您要删除或插入元素的位置,第二个是删除计数,第三个(可选)是您要插入的新元素。

                  【讨论】:

                  • 谢谢。好的,但是我需要多次调用它,每次递增索引。
                  • @cimak for (var i = 0; i &lt; a.length; i++) { if ( i % 2) { a.splice(i, 0, {value: 255}); } }
                  • @Vidul 那效率会非常低。
                  • @Ghazgkull 绝对:)
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-08-03
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多