【问题标题】:Terse way to intersperse element between all elements in JavaScript array?在 JavaScript 数组中的所有元素之间散布元素的简洁方法?
【发布时间】:2016-09-04 20:19:50
【问题描述】:

假设我有一个数组var arr = [1, 2, 3],我想用一个元素分隔每个元素,例如。 var sep = "&",所以输出是[1, "&", 2, "&", 3]

另一种思考方式是我想做 Array.prototype.join (arr.join(sep)) 而不是字符串(因为我尝试使用的元素和分隔符是对象,而不是字符串)。

在 es6/7 或 lodash 中是否有一种功能/漂亮/优雅的方式可以做到这一点,而不会让人感觉像这样笨重:

_.flatten(arr.map((el, i) => [el, i < arr.length-1 ? sep : null])) // too complex

_.flatten(arr.map(el => [el, sep]).slice(0,-1) // extra sep added, memory wasted

甚至

arr.reduce((prev,curr) => { prev.push(curr, sep); return prev; }, []).slice(0,-1)
// probably the best out of the three, but I have to do a map already
// and I still have the same problem as the previous two - either
// inline ternary or slice

编辑:Haskell 有这个功能,叫做intersperse

【问题讨论】:

    标签: javascript arrays ecmascript-6 lodash


    【解决方案1】:

    使用生成器:

    function *intersperse(a, delim) {
      let first = true;
      for (const x of a) {
        if (!first) yield delim;
        first = false;
        yield x;
      }
    }
    
    console.log([...intersperse(array, '&')]);
    

    感谢@Bergi 指出输入可以是任何可迭代的有用概括。

    如果你不喜欢使用生成器,那么

    [].concat(...a.map(e => ['&', e])).slice(1)
    

    【讨论】:

    • flatMap 使这变得更加容易:a.flatMap(e =&gt; ['&amp;', e]).slice(1)
    【解决方案2】:

    reduce 函数中的扩展和显式返回将使其更简洁:

    const intersperse = (arr, sep) => arr.reduce((a,v)=>[...a,v,sep],[]).slice(0,-1)
    // intersperse([1,2,3], 'z')
    // [1, "z", 2, "z", 3]
    

    【讨论】:

      【解决方案3】:

      在 ES6 中,您将编写一个生成器函数,该函数可以生成一个迭代器,该迭代器生成带有散布元素的输入:

      function* intersperse(iterable, separator) {
          const iterator = iterable[Symbol.iterator]();
          const first = iterator.next();
          if (first.done) return;
          else yield first.value;
          for (const value of iterator) {
              yield separator;
              yield value;
          }
      }
      
      console.log(Array.from(intersperse([1, 2, 3], "&")));
      

      【讨论】:

      • yield *[separator, value] :-)
      • @torazaburo:我永远不会想到这一点。有趣,但只适合打高尔夫球:-)
      【解决方案4】:

      一种直接的方法可能是向 reduce 函数提供一个初始数组,该数组的大小比原始数组的两倍小一,填充用于穿插的字符。然后将索引 i 处的原始数组的元素映射到最初馈送的目标数组中的 2*i 将完美地完成这项工作..

      在这种方法中,我看不到(m)任何冗余操作。此外,由于我们在设置数组大小后没有修改任何数组大小,因此我不希望任何后台任务运行以进行内存重新分配、优化等。 另一个好处是使用标准数组方法,因为它们会检查各种不匹配等等。

      此函数返回一个新数组,其中被调用的数组项与提供的参数穿插。

      var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
      Array.prototype.intersperse = function(s){
        return this.reduce((p,c,i) => (p[2*i]=c,p), new Array(2*this.length-1).fill(s));
      }
      document.write("<pre>" + JSON.stringify(arr.intersperse("&")) + "</pre>");

      【讨论】:

        【解决方案5】:

        使用reduce 但不使用slice

        var arr = ['a','b','c','d'];
        var lastIndex = arr.length-1;
        arr.reduce((res,x,index)=>{
           res.push(x);
           if(lastIndex !== index)
            res.push('&');
          return res;
        },[]);
        

        【讨论】:

          【解决方案6】:

          javascript 有一个方法 join() 和 split()

          var arr = ['a','b','c','d'];
          arr = arr.join('&');
          document.writeln(arr);
          

          输出应该是:a&b&c&d

          现在再次分裂:

          arr = arr.split("");
          

          arr 现在是:

          arr = ['a','&','b','&','c','&','d'];
          

          【讨论】:

          • 正如我上面提到的,本机连接方法不起作用,因为我没有使用字符串。我会用一个不同的例子来更新这个问题。
          • 在下方添加了新的解决方案。
          • 我们只希望字符串中没有包含“&”的数组元素。
          【解决方案7】:

          如果您的依赖项中有Ramda,或者如果您愿意添加它,那里有intersperse 方法。

          来自文档:

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

          分派到第二个参数的 intersperse 方法,如果存在的话。

          R.intersperse('n', ['ba', 'a', 'a']); //=> ['ba', 'n', 'a', 'n', 'a']
          

          或者您可以查看源代码,了解其中一种在您的代码库中执行此操作的方法。 https://github.com/ramda/ramda/blob/v0.24.1/src/intersperse.js

          【讨论】:

            【解决方案8】:

            您可以使用Array.from 创建一个具有最终大小的数组,然后使用回调参数实际填充它:

            const intersperse = (arr, sep) => Array.from(
                { length: Math.max(0, arr.length * 2 - 1) }, 
                (_, i) => i % 2 ? sep : arr[i >> 1]
            );
            // Demo:
            let res = intersperse([1, 2, 3], "&");
            console.log(res);

            【讨论】:

              【解决方案9】:

              单线和快速

              const intersperse = (ar,s)=>[...Array(2*ar.length-1)].map((_,i)=>i%2?s:ar[i/2]);
              
              console.log(intersperse([1, 2, 3], '&'));

              【讨论】:

                【解决方案10】:
                if (!Array.prototype.intersperse) {
                  Object.defineProperty(Array.prototype, 'intersperse', {
                    value: function(something) {
                      if (this === null) {
                        throw new TypeError( 'Array.prototype.intersperse ' + 
                          'called on null or undefined' );
                      }
                      var isFunc = (typeof something == 'function')
                
                      return this.concat.apply([], 
                        this.map(function(e,i) { 
                          return i ? [isFunc ? something(this[i-1]) : something, e] : [e] }.bind(this)))
                    }
                  });
                }
                

                【讨论】:

                  【解决方案11】:

                  您还可以使用以下内容:

                  var arr =['a', 'b', 'c', 'd'];
                  arr.forEach(function(element, index, array){
                      array.splice(2*index+1, 0, '&');
                  });
                  arr.pop();
                  

                  【讨论】:

                    【解决方案12】:

                    我的看法:

                    const _ = require('lodash');
                    
                    _.mixin({
                        intersperse(array, sep) {
                            return _(array)
                                .flatMap(x => [x, sep])
                                .take(2 * array.length - 1)
                                .value();
                        },
                    });
                    
                    // _.intersperse(["a", "b", "c"], "-")
                    // > ["a", "-", "b", "-", "c"]
                    

                    【讨论】:

                      【解决方案13】:

                      const arr = [1, 2, 3];
                      
                      function intersperse(items, separator) {
                        const result = items.reduce(
                          (res, el) => [...res, el, separator], []);
                        result.pop();
                        return result;
                      }
                      
                      console.log(intersperse(arr, '&'));

                      【讨论】:

                        【解决方案14】:

                        几年后,这是一个递归生成器解决方案。享受吧!

                        const intersperse = function *([first, ...rest], delim){
                            yield first;
                            if(!rest.length){
                              return;
                            }
                            yield delim;
                            yield * intersperse(rest, delim);
                        };
                        console.log([...intersperse(array, '&')]);
                        

                        【讨论】:

                        • 原则上我想赞成这个,但是如果在运行时没有尾调用优化,它可能不是最好的选择。
                        【解决方案15】:
                        export const intersperse = (array, insertSeparator) => {
                          if (!isArray(array)) {
                            throw new Error(`Wrong argument in intersperse function, expected array, got ${typeof array}`);
                          }
                        
                          if (!isFunction(insertSeparator)) {
                            throw new Error(`Wrong argument in intersperse function, expected function, got ${typeof insertSeparator}`);
                          }
                        
                          return flatMap(
                            array,
                            (item, index) => index > 0 ? [insertSeparator(item, index), item] : [item] // eslint-disable-line no-confusing-arrow
                          );
                        };
                        

                        【讨论】:

                          【解决方案16】:

                          为不使用连接方法的对象更新:

                          for (var i=0;i<arr.length;i++;) {
                              newarr.push(arr[i]);
                              if(i>0) { 
                                newarr.push('&'); 
                               }    
                          }
                          

                          newwarr 应该是:

                          newarr = ['a','&','b','&','c','&','d']; 
                          

                          【讨论】:

                          • 这颠倒了数组元素的顺序。
                          • 首先,由于for 语句末尾的额外分号,这会产生语法错误。其次,它导致第一个元素之后没有&符号,而末尾有一个额外的&符号。
                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2019-06-09
                          • 2019-08-06
                          • 1970-01-01
                          • 2017-09-25
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多