使用数组分隔符连接数组序列("散布")

时间:2016-09-26 07:45:24

标签: javascript arrays lodash

是否有一个函数可以让我连接多个数组,它们之间有分隔符(分隔符也是数组),类似于join的工作原理但不限于字符串?

该函数可以是标准JS或主要库的一部分,例如lodash(这就是它在标签中被引用的原因)。

以下是一个使用示例:

let numbers = [[1], [2], [3]];
let result = _.joinArrays(numbers, [0]);
console.log(result); 
//printed: [1, 0, 2, 0, 3]

这类似于:

let strings = ["a", "b", "c"];
let result = strings.join(",");
console.log(result);
//printed: "a,b,c";

但是,join无法使用,因为它会将值转换为字符串,我不想发生这种情况。

但它适用于任何类型。

7 个答案:

答案 0 :(得分:8)

您可以简单地使用<a href="" onclick="window.history.go(-1); return false;">back</a> 来连接数组,并推送您想要用作分隔符的内容。

array.reduce

答案 1 :(得分:3)

Matrix Interspersion

这里是完整的monty。发疯。

&#13;
&#13;
var numbers = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
],
  delimiters = [
  ',', '-', 'x'
];

// matrix interspersion, delimiters into numbers's children
// the rank/order/whatevs of the matrix can be arbitrary and variable
numbers.forEach((x, i) => {
  for (var j = 1, l = x.length; j <= l; j+=2 )
    x.splice(j, 0, delimiters[i]);
})

alert( "Matrix interspersed: " + JSON.stringify(numbers) );

// normal interspersion, a static delimiter into numbers
for (var j = 1, l = numbers.length; j <= l; j+=2 )
    numbers.splice(j, 0, ' AND ');

alert( "Outer array interspersed: " + JSON.stringify(numbers) );

// flattening a 2 rank array into a single array
var flattened = Array.prototype.concat.apply([], numbers);

alert( "Flattened: " + JSON.stringify(flattened) );
&#13;
&#13;
&#13;

答案 2 :(得分:0)

var result = [].concat.apply([], numbers);

console.log(result)

答案 3 :(得分:0)

如果需要,您可以使用Array#reduce并返回包含项目和粘合的数组。

&#13;
&#13;
const join = (array, glue) => array.reduce((a, b) => a.concat(glue, b));

var numbers = [[1], [2], [3]];

console.log(join(numbers, [0]));
console.log(join(numbers, [42, 43]));
console.log(join([[1]], [0]));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

答案 4 :(得分:0)

这是一个执行此功能的函数的实现,带有一些额外的逻辑,以防其他人想要这样做。我真的在问这是否已经存在。

需要lodash。

export function intersperse(arrs, delimeter) {
    let joined = [];
    for (var i = 0; i < arrs.length; i++) {
        let arr = arrs[i];
        if (!arr) continue; //handle sparse arrays
        joined.push(...arr);
        if (i === arrs.length - 1) break;
        if (_.isFunction(delimeter)) {
            joined.push(...delimeter());
        } else if (_.isArray(delimeter)) {
            joined.push(...delimeter);
        } else {
            throw new Error("unknown type");
        }
    }
    return joined;
}

答案 5 :(得分:0)

这里有许多好的答案,包括4Castle的评论。至于改变,我想为这项工作开发一个通用的Array.prototype.intersperse()

在功能性JS中,我可以为这项工作提出3种选择;

Array.prototype.intersperse_1 = function(s){
  return this.reduce((p,c,i) => (p[2*i]=c,p), new Array(2*this.length-1).fill(s));
};
Array.prototype.intersperse_2 = function(s){
  return this.reduce((p,c,i) => (i ? p.push(s,c) : p.push(c),p),[]);
};
Array.prototype.intersperse_3 = function(s){
  return this.reduce((p,c,i) => i ? p.concat([s],[c]) : p.concat([c]),[]);
};

你应该远离第三个,因为.concat()是功能JS中最昂贵的操作之一。它甚至无法完成100K项目的工作。

另一方面,虽然在小尺寸阵列中总是稍微快一点,但在FF和Chrome中,第一个在非常大的阵列中比第二个快2倍甚至更快。即,第一次在不到1000毫秒内散布一个10M物品阵列,而对于相同的工作,第二次在2000-2500毫秒内散布。当然,处理这个大小是不可能的。

因此在这种特殊情况下,与定制解决方案相比,它可能会更昂贵,因为我们必须将结果映射到原始值,但我想仍然值得注意以下代码。我确信当阵列长度超过某个数字时,.concat()采用量身定制的解决方案将落后于此。

Array.prototype.intersperse = function(s){
  return this.reduce((p,c,i) => (p[2*i]=c,p), new Array(2*this.length-1).fill(s));
}

var arr = [[1],[2],[3]],
 result = arr.intersperse([0])
             .map(e => e[0]);
console.log(JSON.stringify(result));

答案 6 :(得分:0)

如前所述,最简单的方法是

function intercalate(glue, arr){
    return arr.reduce((acc, v) => acc.concat(glue, v));
}

但这不是最好的方法,因为它会在每次迭代时创建一个新的(中间)数组,然后抛弃它。这对于这个短的数组值无关紧要,但是如果您打算在更长的数组上使用它,您可能会注意到这种影响。

最好是创建一个数组并将值推入其中,因为它们会进入。

function intercalate(glue, arr){
    const push = (acc, v) => (Array.isArray(v)? acc.push(...v): acc.push(v), acc);
    return arr.reduce((acc, v, i) => push(i===0? acc: push(acc, glue), v), []);
}

但是由于这个数据逐渐增加,它可能仍然需要分配更大的内存块并复制数据。这些任务非常高效,但仍然没有必要(imo);我们可以做得更好。

我们首先创建一个包含所有数组和中间分隔符的列表,然后使用concat.apply([], list)将其展平。因此,我们生成一个中间数组,我们可以提前计算其大小,其余的是Array.concat的问题,它是底层实现。

function intersperse(delimiter, arr){
    if(!arr.length) return [];
    let j = 0, push = (acc, v) => (acc[j++] = v, acc);
    return arr.reduce((acc, v) => push(j===0? acc: push(delimiter, glue), v), Array(2*arr.length-1));
}
//or
function intersperse(delimiter, arr){
    if(!arr.length) return [];
    var out = Array(2*arr.length-1);
        out[0] = arr[0];
    for(var i=1, j=1; j<out.length;){
        out[j++] = delimiter;
        out[j++] = arr[i++];
    }
    return out;
}

//and

function intercalate(glue, arr){
    var emptyArray = [];
    return arr.length? 
        emptyArray.concat.apply(emptyArray, intersperse(glue, arr)): 
        emptyArray;
}

Wich版本将是最好/最快的,最后,并不容易分辨,因为它可能取决于传递的值,而JIT编译器是否优化了它的s ***。我提出了我的观点,由你来选择你使用的版本/实现。

对于第一个版本:您可能更愿意不将它放入lib中,但是主要将其写入内联(它简短且足够简单),因此JIT编译器可能不会尝试在不同的调用(#monomorphic function / code)之间找到一些常见类型,从而单独优化每个出现。另一方面,这可能是过早优化。这取决于你。