I want to merge arrays a little bit different way. I have 2 or more arrays like:
var array1 = ["apple", "banana"];
var array2 = ["apple", "apple", "orange"];
I want the output:
var array3 = ["apple", "apple", "banana", "orange"];
So if any given array has a variable in it more than once, merge algorithm should keep all of them from that array.
I saw some code that prevents duplication but it gives outputs like this:
var array3 = ["apple", "banana", "orange"];
for more example:
var arr1 = [1,2,3,4];
var arr2 = [1,1,2,4,5,5,5];
var arr3 = [1,3,3,5,5];
I want the output:
var array4 = [1,1,2,3,3,4,5,5,5];
How can I do this?
I want to merge arrays a little bit different way. I have 2 or more arrays like:
var array1 = ["apple", "banana"];
var array2 = ["apple", "apple", "orange"];
I want the output:
var array3 = ["apple", "apple", "banana", "orange"];
So if any given array has a variable in it more than once, merge algorithm should keep all of them from that array.
I saw some code that prevents duplication but it gives outputs like this:
var array3 = ["apple", "banana", "orange"];
for more example:
var arr1 = [1,2,3,4];
var arr2 = [1,1,2,4,5,5,5];
var arr3 = [1,3,3,5,5];
I want the output:
var array4 = [1,1,2,3,3,4,5,5,5];
How can I do this?
Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Jan 4, 2015 at 21:50 u.zzzu.zzz 834 bronze badges 6-
1
console.log(array1.concat(array2).sort())
, is that what you mean? – Xotic750 Commented Jan 4, 2015 at 22:00 - 2 @Xotic750: No. That would preserve every instance of an element, not just the greatest number of an element in any array. Look at his desired outputs carefully, especially in the last example. He wants two 1's, in the output, not four. – Robert Harvey Commented Jan 4, 2015 at 22:02
- @RobertHarvey Aha, I see. (I think) – Xotic750 Commented Jan 4, 2015 at 22:05
- @u.zzz What have you tried so far? – Xotic750 Commented Jan 4, 2015 at 22:13
- @Xotic750 I am a beginner. I tried algorithms in this post but they are not working as I want. – u.zzz Commented Jan 4, 2015 at 22:17
5 Answers
Reset to default 2Here's one way to do it by counting the occurrences of each item in each array:
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);
Working demo: http://jsfiddle/jfriend00/dtn6zw4m/
Here is a solution using 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)));
I like to use ramda (http://ramdajs./docs/index.html) for this stuff
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.pose(R.uniq, R.flatten)(allArrays);
var getItemCounts = R.countBy(function(item) {
return item;
});
var itemCounts = R.map(function(arr) {
return getItemCounts(arr);
})(allArrays);
var bined = [];
R.forEach(function(item) {
var countsForItem = R.pluck(item, itemCounts);
var maxCount = R.max(countsForItem);
bined.push.apply(bined, R.repeatN(item, maxCount));
})(allValues);
console.log(bined.sort());
JSFiddle: http://jsfiddle/pcr0q1xa/3/
Ramda is your friend.
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)))
<script src="http://cdnjs.cloudflare./ajax/libs/ramda/0.22.1/ramda.min.js"></script>
Untested and not JS, but I think this is what you are looking for. I have just tested it manually, it worked for your test cases.
while items in lista or items in listb
pare 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