【问题标题】:How to merge arrays in javascript in a different way?如何以不同的方式合并javascript中的数组?
【发布时间】:2015-03-02 11:19:11
【问题描述】:

我想以不同的方式合并数组。 我有 2 个或更多数组,例如:

var array1 = ["apple", "banana"];

var array2 = ["apple", "apple", "orange"];

我想要输出:

var array3 = ["apple", "apple", "banana", "orange"];

因此,如果任何给定数组中不止一次包含一个变量,合并算法应该将所有这些变量都保留在该数组中。

我看到了一些防止重复的代码,但它给出的输出如下:

var array3 = ["apple", "banana", "orange"];

更多示例:

var arr1 = [1,2,3,4];

var arr2 = [1,1,2,4,5,5,5];

var arr3 = [1,3,3,5,5];

我想要输出:

var array4 = [1,1,2,3,3,4,5,5,5];

我该怎么做?

【问题讨论】:

  • console.log(array1.concat(array2).sort()),你是这个意思吗?
  • @Xotic750:不。这将保留元素的每个实例,而不仅仅是任何数组中最大数量的元素。仔细查看他想要的输出,尤其是在最后一个示例中。他希望输出中有两个 1,而不是四个。
  • @RobertHarvey 啊哈,我明白了。 (我认为)
  • @u.zzz 到目前为止你尝试了什么?
  • @Xotic750 我是初学者。我在this 帖子中尝试了算法,但它们没有按我的意愿工作。

标签: javascript arrays merge array-merge


【解决方案1】:

这是一种计算每个数组中每个项目的出现次数的方法:

var arr1 = [1,2,3,4];
var arr2 = [1,1,2,4,5,5,5];
var arr3 = [1,3,3,5,5];

function joinCommon(/* list of arrays */) {
    var arr, arrayCounts, masterList = {}, item, output;
    // for each array passed in
    for (var i = 0; i < arguments.length; i++) {
        arr = arguments[i];
        arrayCounts = {};
        // iterate each array
        for (var j = 0; j < arr.length; j++) {
            item = arr[j];
            if (!arrayCounts[item]) {
                arrayCounts[item] = 1;
            } else {
                ++arrayCounts[item];
            }
            // now keep master list and master counts
            if (!masterList[item]) {
                masterList[item] = {cnt: 1, val: item};
            } else {
                masterList[item].cnt = Math.max(masterList[item].cnt, arrayCounts[item]);
            }
        }
    }
    // now output result
    output = [];
    for (var i in masterList) {
        for (var j = 0; j < masterList[i].cnt; j++) {
            output.push(masterList[i].val);
        }
    }
    return output;    
}

var results = joinCommon(arr1, arr2, arr3);

工作演示:http://jsfiddle.net/jfriend00/dtn6zw4m/

【讨论】:

  • ["1","1","2","3","3","4","5","5","5"] !== [1,1,2,3,3,4,5,5,5]
  • @Xotic750 - 已经在努力解决这个问题。对字符串值工作正常,但由于所有属性名称都是字符串,所以数字被转换为字符串。现在通过跟踪与属性名称分开的实际值来修复。
  • 认为值得指出,并且完全相信您会解决它。 ;)
  • 只是为了感兴趣,jsPerf 的 ECMA3 与 ECMA5 解决方案。
【解决方案2】:

这是使用 ECMA5 的解决方案。

Javascript

function indexOf(items, value) {
    return items.map(function (subitem) {
        return subitem.value;
    }).indexOf(value);
}

function countItems(previous, item) {
    var atIndex = indexOf(previous, item);

    if (atIndex !== -1) {
        previous[atIndex].count += 1;
    } else {
        previous.push({
            value: item,
            count: 1
        });
    }

    return previous;
}

function mergeCounts(item) {
    var atIndex = indexOf(this, item.value);

    if (atIndex === -1) {
        this.push(item);
    } else if (this[atIndex].count < item.count) {
        this[atIndex] = item;
    }
}

function expandCounts(previous, item) {
    var iter;

    for (iter = 0; iter < item.count; iter += 1) {
        previous.push(item.value);
    }

    return previous;
}

function mergeArg(items, arg) {
    arg.reduce(countItems, []).forEach(mergeCounts, items);

    return items;
}

function mergeMaxItems() {
    return [].reduce.call(arguments, mergeArg, []).reduce(expandCounts, []);
}

var arr1 = [1, 2, 3, 4],
    arr2 = [1, 1, 2, 4, 5, 5, 5],
    arr3 = [1, 3, 3, 5, 5];

document.body.appendChild(document.createTextNode(mergeMaxItems(arr1, arr2, arr3)));

【讨论】:

    【解决方案3】:

    我喜欢使用 ramda (http://ramdajs.com/docs/index.html) 来处理这些东西

    var arr1 = [1,2,3,4];
    
    var arr2 = [1,1,2,4,5,5,5];
    
    var arr3 = [1,3,3,5,5];
    
    var allArrays = [arr1, arr2, arr3];
    
    var allValues = R.compose(R.uniq, R.flatten)(allArrays);
    
    var getItemCounts = R.countBy(function(item) {
       return item;
    });
    
    var itemCounts = R.map(function(arr) {
       return getItemCounts(arr);
    })(allArrays);
    
    var combined = [];
    R.forEach(function(item) {
       var countsForItem = R.pluck(item, itemCounts);
       var maxCount = R.max(countsForItem);
       combined.push.apply(combined, R.repeatN(item, maxCount));
    })(allValues);
    
    console.log(combined.sort());
    

    JSFiddle:http://jsfiddle.net/pcr0q1xa/3/

    【讨论】:

    • [1,1,1,1,1,1,2,2,2,2,3,3,3,3,3] !== [1,1,2,3,3,4,5,5,5]
    • 看起来好多了。 :)
    【解决方案4】:

    Ramda 是你的朋友。

    function merge () {
      return R.chain(R.apply(R.repeat), R.toPairs(R.reduce(
        R.mergeWith(R.max),
        {},
        R.map(R.countBy(R.identity), arguments)
      )))
    }
    
    var array1 = ["apple", "banana"];
    
    var array2 = ["apple", "apple", "orange"];
    
    console.log(JSON.stringify(merge(array1, array2)))
    
    var arr1 = [1,2,3,4];
    
    var arr2 = [1,1,2,4,5,5,5];
    
    var arr3 = [1,3,3,5,5];
    
    console.log(JSON.stringify(merge(arr1, arr2, arr3)))
    &lt;script src="http://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"&gt;&lt;/script&gt;

    【讨论】:

      【解决方案5】:

      未经测试而不是 JS,但我认为这就是您要寻找的。 我刚刚手动测试了它,它适用于您的测试用例。

      while items in lista or items in listb
          compare a.head, b.head
          if a.head is smaller or b.is_empty then 
               append a.head to output
               a.drophead
          else if b.head is smaller or a.is_empty then
               append b.head to output
               b.drophead
          else
               append b.head to output
               b.drophead
               a.drophead
      

      【讨论】:

        猜你喜欢
        • 2020-08-18
        • 2022-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多