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?
Here'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.net/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.com/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.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/
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.com/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
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
Related
So I have a var size that may vary which counts how many arrays are passed in an argument.
concatenate(...arg){
let size = arg.length ;
}
I want to use spread syntax by a number of times equal with that size ,more specific I want to concatenate all arrays, for example :
let arr1 = [1,2,3];
let arr2 = [3,2,1];
let arr3 = [4,5,6];
// unknown number of array
let finalArr = [...arr1,...arr2,...arr3,...etc];
So what I want to ask you is to replace the hardcoded finalArr, with a template that can take care of that for me?
What I tried so far :
// Arrays share the same content,ex : Arr : {content:[Arr(3)}
function concatenate(...arg){
let size = arg.length;
let arrays = arg;
let tmplt = Arr(size+1).join(`Arr${size}`);
let finalArr = [];
while(size>=0){
finalArr= [tmplt];
size--;
}
return finalArr;
}
//input
let var1 = [{content:[2,9,10]}];
let var2 = [{content:[3,1,3]}];
let var3 = [{content:[9,1,8]}];
var1.concatenate(var2,var3);
// expected output
[2,9,10,3,1,3,9,1,8]
Finally, I try to reproduce the concat() method of Array within a class List that I made. The rules are : no Array.prototype.methods() allowed .
Full code so far :
class List {
constructor(items){
this.content = !items ? [] : items;
this.size = this.length();
}
length(arg=0){
let size = arg;
if(!this.content[arg]){
return size;
}
size++;
return this.length(size);
}
append(arg){
if(this.size ==0 && this.size == arg.size){
this.content = new List();
return this.content;
}
this.content = [...this.content,...arg.content]
return this.content;
}
concatenate(...arg){
let test = arg;
let size = 0;
let final = [];
while(test[size]!=undefined){
// final += [...test[size].content];
size++;
let x = Array(size+1).join(`...test${size}.content`);
while(size>=0){
size--;
}
}
}
}
let aList = new List([2,9,10]);
let anotherList = new List([3,14,1]);
let thirdList = new List([9,0,8]);
aList.concatenate(anotherList,thirdList);
You can use a generator function which takes arrays delegates to each of the iterators. This allows you to flatten as many arrays as you want and can be used with spread notation:
function* concat(...arrays) {
for (const array of arrays)
yield* array;
}
function concatenate(...arg){
return [...concat(...arg)];
}
let arr1 = [1,2,3];
let arr2 = [3,2,1];
let arr3 = [4,5,6];
let finalArr = concatenate(arr1, arr2, arr3);
console.log(finalArr);
.as-console-wrapper { max-height: 100% !important; }
You could take nested for loops.
function concatenate(...args) {
const result = [];
for (const array of args) for (const { content } of array) result.push(...content);
return result;
}
const
var1 = [{ content: [2, 9, 10] }],
var2 = [{ content: [3, 1, 3] }],
var3 = [{ content: [9, 1, 8] }];
console.log(...concatenate(var1, var2, var3)); // [2, 9, 10, 3, 1, 3, 9, 1, 8]
You can use the .push method on arrays to concatenate them.
let arr1 = [1,2,3];
let arr2 = [3,2,1];
let arr3 = [4,5,6];
function concatenate(...arg){
let size = arg.length ;
let finalArr = [];
for(let i = 0; i < size; i++)
finalArr.push(...arg[i]);
return finalArr
}
finalArr = concatenate(arr1, arr2, arr3);
console.log(finalArr);
I have a JavaScript array with 8 elements and some elements are repeating. I want to create separate arrays for identical elements.
example:
original array is [1,1,1,3,3,1,2,2]
resulting arrays will be [1,1,1,1],[3,3],[2,2]
I want a function similar to this:
var array=[1,1,1,3,3,1,2,2];
var createNewArrays=function(array){
for (var i = 0; i < array.length; i++) {
for (var j = 0; j < array.length; j++) {
}
}
};
You could use a hash table as reference to the sub arrays for the collection.
var array = [1, 1, 1, 3, 3, 1, 2, 2],
result = [];
array.forEach(function (a) {
a in this || result.push(this[a] = []);
this[a].push(a);
}, Object.create(null));
console.log(result);
var arr = [1,1,1,3,3,1,2,2];
var hash = Object.create(null);
var result = arr.reduce(function(r, n) {
if(!hash[n]) {
hash[n] = [];
r.push(hash[n]);
}
hash[n].push(n);
return r;
}, []);
console.log(result);
And an ES6 solution that uses Map, and spread:
const arr = [1,1,1,3,3,1,2,2];
const result = [...arr.reduce((r, n) =>
r.set(n, (r.get(n) || []).concat(n)),
new Map()).values()];
console.log(result);
Let's assume you want the resulting arrays to be properties on an object keyed by the value they represent. You just loop through the array, creating or adding to the arrays on the object properties as you go:
var array=[1,1,1,3,3,1,2,2];
var result = {};
array.forEach(function(entry) {
(result[entry] = result[entry] || []).push(entry);
});
console.log(result);
That's a bit dense, here's a clearer version:
var array=[1,1,1,3,3,1,2,2];
var result = {};
array.forEach(function(entry) {
var subarray = result[entry];
if (!subarray) {
subarray = result[entry] = [];
}
subarray.push(entry);
});
console.log(result);
i have two array:
array1 = [35,433]; array2 = [70,154,73];
Need to be arrays :
result[0] = [35,70]; result[1] = [35,154]; result[2] =
[35,73]; result[3] = [433,70]; result[4] = [433,154];
result[5] = [433,73];
My code:
var groupAttribute = [];
groupAttribute[0] = ['35'=>'bla','433'=>'blu'];
groupAttribute[1] = ['70'=>'fre','154'=>'nuy','73'=>'tres'];
var counter = 0;
var countAttributes = 5;
var combinat = [];
for (var i = 0, j = 0;; j++) {
if (i >= groupAttribute.length && j >= countAttributes) {
break;
}
if (i >= groupAttribute.length) {
i = 0;
}
combinat[counter] = [];
$.each(groupAttribute[i],function(key, attribute) {
combinat[counter].push(parseInt(key));
counter++;
i++;
});
}
console.log(combinat);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
Pls help me
Two separated array
var array1 = [35,433];
var array2 = [70,154,73];
var newArr = [];
array1.forEach(function(a) {
array2.forEach(function(b) {
newArr.push([a, b])
})
})
console.log(newArr)
If nested depth is unknown:
var arr = [[35,433], [70,154,73], [5,1]];
function Permute(arr) {
if (arr.length === 1) {
return arr[0];
}
var res = [];
var sliced = Permute(arr.slice(1));
arr[0].forEach(function(a) {
sliced.forEach(function(b) {
res.push([a].concat(b))
})
})
return res;
}
var newArr = Permute(arr);
console.log(newArr)
Hope this helps
Here's a purely function/recursive solution that works with any positive number of arrays.
let array1 = [35, 433];
let array2 = [70, 154, 73];
let array3 = [1, 2, 3];
let result = combine(array1, array2, array3 /* more arrays */ );
function combine(arr, ...rest) {
if (!rest.length) return arr.map(n => [n]);
const sub = combine(...rest);
return arr.reduce((a, n) => [...a, ...sub.map(a2 => [n, ...a2])], [])
}
console.log(result);
For the matrix diff you asked about in the comment, do this:
var arr1 = [[35,70],[433,70],[35,73],[433,73],[35,154],[433,154]];
var arr2 = [[433,70],[433,154],[433,73],[35,154]];
var result = [
...aNotInB(arr1, arr2),
...aNotInB(arr2, arr1),
];
function aNotInB(a, b) {
return a.filter(([x, y]) =>
!b.some(([x2, y2]) => x == x2 && y == y2)
)
}
console.log(result);
Suppose I have an array like this:
var arr = [];
arr["india"] = 7;
arr["indonesia"] = 3;
arr["usa"] = 1;
[india: 7, indonesia: 3, usa: 1]
I need to get an array like [india: (7/11*100), indonesia: (3/11*100), usa: (1/11*100)] , i.e., to get the percentage of each country value using a single loop in javascript. How can I achieve it ?
You can use array#reduce to sum up all values and then calculate percentages inside array#map
var arr = {};
arr["india"] = 7;
arr["indonesia"] = 3;
arr["usa"] = 1;
let sum = Object.keys(arr).reduce((s,k) => s += arr[k], 0);
var result = Object.keys(arr).map(k => ({[k] : (arr[k]/sum * 100).toFixed(2)}));
console.log(result);
If your objects is like this var arr = {india: 7, indonesia: 3, usa: 1};, you can do it in this way.
var arr = {india: 7, indonesia: 3, usa: 1};
var sum = 0;
//Finding the sum
for(key in arr){
sum += arr[key];
}
console.log("Sum of the object values is = " + sum);
//Finding the average
for(key in arr){
arr[key] = (arr[key]/sum)*100;
}
console.log(arr);
Loop through each key and reassigned the val like this:
var countries = [];
countries["india"] = 7;
countries["indonesia"] = 3;
countries["usa"] = 1;
for (var country in countries){
if (countries.hasOwnProperty(country)) {
countries[country] = (countries[country] / 11 * 100).toFixed(2)
}
}
console.log(countries)
[india: 7, indonesia: 3, usa: 1]is wrong, you need an object, like {india: 7, indonesia: 3, usa: 1}
So, I think you need an function to do what you need, simple:
var obj = {india: 7, indonesia: 3, usa: 1}
const getPercent = (obj) {
let sum = 0
for (key in obj) {
sum += obj[key]
}
for (key in obj) {
obj[key] = (obj[key]/sum)*100
}
return obj
}
Once you change the obj, you run getPercent(obj), then you get a return, that is what's you need.
May helpful.
So, suppose you have a valid array:
var myArray = { 'key1': 2, 'key2': 5, 'key3': 14 };
/* iterates through an associative array, calculates each percentage and
adds it to a similar associative array
The percentages are not rounded
*/
function getPercentagePerKey(myArray) {
var sum = getSum(myArray);
var arrayWithPercentages = [];
for (key in myArray) {
val = myArray[key];
percentage = (val / sum) * 100;
arrayWithPercentages.push({key, percentage});
}
return arrayWithPercentages;
}
/* returns the sum given from an 'associative' array */
function getSum(myArray) {
var sum = 0;
for (key in myArray) {
sum += myArray[key];
}
return sum;
}
percentageArray = getPercentagePerKey(myArray);
console.log(percentageArray);
0: {key: "key1", percentage: 9.523809523809524}
1: {key: "key2", percentage: 23.809523809523807}
2: {key: "key3", percentage: 66.66666666666666}
You can make getters from object properties if it is allowed:
var arr = {};
arr["india"] = 7;
arr["indonesia"] = 3;
arr["usa"] = 1;
var sum = 0;
var percent = function(n){
return function(){ return n/sum*100; }
}
for (var k in arr) {
sum+=arr[k];
arr[k]=percent(arr[k]);
}
console.log(arr.india());
console.log(arr.usa());
console.log(arr.indonesia());
This question already has answers here:
Simplest code for array intersection in javascript
(40 answers)
Closed 3 years ago.
I have two arrays, and I want to be able to compare the two and only return the values that match. For example both arrays have the value cat so that is what will be returned. I haven't found anything like this. What would be the best way to return similarities?
var array1 = ["cat", "sum","fun", "run"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];
//if value in array1 is equal to value in array2 then return match: cat
You can use :
const intersection = array1.filter(element => array2.includes(element));
Naturally, my approach was to loop through the first array once and check the index of each value in the second array. If the index is > -1, then push it onto the returned array.
Array.prototype.diff = function(arr2) {
var ret = [];
for(var i in this) {
if(arr2.indexOf(this[i]) > -1){
ret.push(this[i]);
}
}
return ret;
};
My solution doesn't use two loops like others do so it may run a bit faster. If you want to avoid using for..in, you can sort both arrays first to reindex all their values:
Array.prototype.diff = function(arr2) {
var ret = [];
this.sort();
arr2.sort();
for(var i = 0; i < this.length; i += 1) {
if(arr2.indexOf(this[i]) > -1){
ret.push(this[i]);
}
}
return ret;
};
Usage would look like:
var array1 = ["cat", "sum","fun", "run", "hut"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];
console.log(array1.diff(array2));
If you have an issue/problem with extending the Array prototype, you could easily change this to a function.
var diff = function(arr, arr2) {
And you'd change anywhere where the func originally said this to arr2.
I found a slight alteration on what #jota3 suggested worked perfectly for me.
var intersections = array1.filter(e => array2.indexOf(e) !== -1);
Hope this helps!
This function runs in O(n log(n) + m log(m)) compared to O(n*m) (as seen in the other solutions with loops/indexOf) which can be useful if you are dealing with lots of values.
However, because neither "a" > 1 nor "a" < 1, this only works for elements of the same type.
function intersect_arrays(a, b) {
var sorted_a = a.concat().sort();
var sorted_b = b.concat().sort();
var common = [];
var a_i = 0;
var b_i = 0;
while (a_i < a.length
&& b_i < b.length)
{
if (sorted_a[a_i] === sorted_b[b_i]) {
common.push(sorted_a[a_i]);
a_i++;
b_i++;
}
else if(sorted_a[a_i] < sorted_b[b_i]) {
a_i++;
}
else {
b_i++;
}
}
return common;
}
Example:
var array1 = ["cat", "sum", "fun", "hut"], //modified for additional match
array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
intersect_arrays(array1, array2);
>> ["cat", "hut"]
Loop through the second array each time you iterate over an element in the first array, then check for matches.
var array1 = ["cat", "sum", "fun", "run"],
array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
function getMatch(a, b) {
var matches = [];
for ( var i = 0; i < a.length; i++ ) {
for ( var e = 0; e < b.length; e++ ) {
if ( a[i] === b[e] ) matches.push( a[i] );
}
}
return matches;
}
getMatch(array1, array2); // ["cat"]
var array1 = [1, 2, 3, 4, 5, 6];
var array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var array3 = array2.filter(function(obj) {
return array1.indexOf(obj) !== -1;
});
You can use javascript function .find()
As it says in MDN, it will return the first value that is true. If such an element is found, find immediately returns the value of that element. Otherwise, find returns undefined.
var array1 = ["cat", "sum", "fun", "run", "cat"];
var array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
found = array1.find((val, index) => {
console.log('index', index) // Stops at 0
return array2.includes(val)
})
console.log(found)
Or use .filter(), which loops through every elements first, then give back the result to you.
var array1 = ["cat", "sum", "fun", "run", "cat"];
var array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
found = array1.filter((val, index) => {
console.log('index', index) // Stops at array1.length - 1
return array2.includes(val)
})
console.log(found)
use lodash
GLOBAL.utils = require('lodash')
var arr1 = ['first' , 'second'];
var arr2 = ['second '];
var result = utils.difference(arr1 , arr2);
console.log ( "result :" + result );
Libraries like underscore and lodash have a utility method called intersection to find matches in arrays passed in. Take a look at: http://underscorejs.org/#intersection
Done as a answer so I can do formatting...
This is the the process you need to go through. Looping through an array for the specifics.
create an empty array
loop through array1, element by element. {
loop through array2, element by element {
if array1.element == array2.element {
add to your new array
}
}
}
If your values are non-null strings or numbers, you can use an object as a dictionary:
var map = {}, result = [], i;
for (i = 0; i < array1.length; ++i) {
map[array1[i]] = 1;
}
for (i = 0; i < array2.length; ++i) {
if (map[array2[i]] === 1) {
result.push(array2[i]);
// avoid returning a value twice if it appears twice in array 2
map[array2[i]] = 0;
}
}
return result;
With some ES6:
let sortedArray = [];
firstArr.map((first) => {
sortedArray[defaultArray.findIndex(def => def === first)] = first;
});
sortedArray = sortedArray.filter(v => v);
This snippet also sorts the firstArr based on the order of the defaultArray
like:
let firstArr = ['apple', 'kiwi', 'banana'];
let defaultArray = ['kiwi', 'apple', 'pear'];
...
console.log(sortedArray);
// ['kiwi', 'apple'];
Iterate on array1 and find the indexof element present in array2.
var array1 = ["cat", "sum","fun", "run"];
var array2 = ["bat", "cat","sun", "hut", "gut"];
var str='';
for(var i=0;i<array1.length;i++){
if(array2.indexOf(array1[i]) != -1){
str+=array1[i]+' ';
};
}
console.log(str)