Merging two Array one after another Javascript [equal length] - javascript

I need to merge two array into one,one after another is there any better way?
for example ,
const arr1 = [1,2,3,4,5];
const arr2 = [a,b,c,d,e];
const resultIWant = [1,a,2,b,3,c,4,d,5,e]

Short and clear if both arrays are same length:
const arr1 = [1,2,3,4,5]
const arr2 = ['a','b','c','d','e']
const res = arr1.flatMap((e, idx) => [e, arr2[idx]])
console.log(res)

This can be done fairly easily using the reduce method. Here is my example below, I iterate through arr1 using reduce() and as I push the current value (c) to the accumulator (a), I also push the value from arr2 of the same index.
In my code below, this looks like a.push(c, arr2[i]) but you could also achieve this using a.push(arr1[i], arr2[i]), using arr1[i] instead of c if you want to keep both push values looking consistent.
const arr1 = [1,2,3,4,5];
const arr2 = ['a','b','c','d','e'];
const result = arr1.reduce((a,c,i) => (a.push(c, arr2[i]), a), []);
console.log(result);

Related

How to compare a part of an array item with a part of an array item from a second array?

If I have two arrays with files
arr1 = ['file1.webp', 'file2.webp', ...];
arr2 = ['file1.jpg', 'file2.png', 'file3.jpg', 'file4.jpg', ...];
how would I check which array items are equal, minus the *.format part?
The idea is that, if there are two equal items, a webp and an alternative source are available. While if an item has no match, no webp source was provided. Both cases would lead to different image handling later on.
I could compare the items inside two arrays like so: let match = arr1.find( val => arr2.includes(val) );
But this compares each entire item. I only want to compare the file names. The formats in which the files were provided need to be cut off, so I get:
arr1 = ['file1', 'file2', ...];
arr2 = ['file1', 'file2', 'file3', 'file4', ...];
I can then filter out all matches between the two arrays. I've been searching for a solution for a real while, but I'm still not sure how to get there.
With a function that trims off the file extension, you can construct a Set of one of the transformed arrays. Then iterate over the other array and check whether its transformed item is in the Set or not:
const arr1 = ['file1.webp', 'file2.webp'];
const arr2 = ['file1.jpg', 'file2.png', 'file3.jpg', 'file4.jpg'];
const transform = str => str.replace(/\.[^.]+$/, '');
const set1 = new Set(arr1.map(transform));
for (const item of arr2) {
if (set1.has(transform(item))) {
console.log('Match for', item);
} else {
console.log('No match for', item);
}
}
You can use filter() with nested some(). To get the file name from complete name use split('.')and get the first element using .split('.')[0]
let arr1 = ['file1.webp', 'file2.webp'];
let arr2 = ['file1.jpg', 'file2.png', 'file3.jpg', 'file4.jpg'];
let res = arr2.filter(a => arr1.some(b => a.split('.')[0] === b.split('.')[0]));
console.log(res)
You could filter by looking to the right side.
const getName = s => s.replace(/\.[^.]+$/, '');
var array1 = ['file1.webp', 'file2.webp'],
array2 = ['file1.jpg', 'file2.png', 'file3.jpg', 'file4.jpg'],
set1 = new Set(array1.map(getName)),
common = array2.filter(s => set1.has(getName(s)));
console.log(common);
write extract method to get value to compare. Just use the extract method in your code. Alternatively, you can build an arr2Obj to not to repeat the searches.
const arr1 = ["file1.webp", "file2.webp"];
const arr2 = ["file1.jpg", "file2.png", "file3.jpg", "file4.jpg"];
const extract = item => item.split(".")[0];
let match = arr1.find(val => arr2.map(x => extract(x)).includes(extract(val)));
console.log(match);
// Alternatively,
const arr2Obj = Object.assign({}, ...arr2.map(x => ({ [extract(x)]: 1 })));
const match2 = arr1.find(val => extract(val) in arr2Obj);
console.log(match2);

Filter array based on presence in another array with different properties

let arr1 = [{itemId:1, name:"item1"}, {itemId:2, name:"item2"},{itemId:3, name:"item3"}]
let arr2 = [{id:1, name:"item1"}, {id:2, name:"item2"}]
How do I filter arr1 based on whether there is a matching item in arr2 where arr1.itemId will be equal to arr2.id
So expected result in this case would be:
[{itemId:1, name:"item1"}, {itemId:2, name:"item2"}]
I have tried searching SO so would be helpful if there is existing question if you could point me in right direction
Thanks
Build up a Set of ids, than filter based on that:
const ids = new Set(arr2.map(it => it.id));
const result = array1.filter(it => ids.has(it.itemId));
You can use Array.prototype.filter() and Array.prototype.some():
const arr1 = [{itemId:1, name:"item1"}, {itemId:2, name:"item2"},{itemId:3, name:"item3"}];
const arr2 = [{id:1, name:"item1"}, {id:2, name:"item2"}];
const result = arr1.filter(({ itemId }) => arr2.some(x => x.id === itemId));
console.log(result);
This will work ok for small arrays, however, if the arrays get big, it is better to create a Set of ids from arr2 and use Set.prototype.has() instead of Array.prototype.some(), this will run in linear time instead of quadratic time.
See the response from #Jonas Wilms.
You can use the following:
let arr1 = [{itemId:1, name:"item1"}, {itemId:2, name:"item2"},{itemId:3, name:"item3"}];
let arr2 = [{id:1, name:"item1"}, {id:2, name:"item2"}];
let arr3 = arr1.filter(obj => arr2.some(other => obj.itemId == other.id));
console.log(arr3);
Which uses Array.prototype.filter() to loop and filter the elements that have a matching items in the second array, using Array.prototype.some().
try
arr1.filter(x=> arr2.some(y=>y.id==x.itemId));
let arr1 = [{itemId:1, name:"item1"}, {itemId:2, name:"item2"},{itemId:3, name:"item3"}]
let arr2 = [{id:1, name:"item1"}, {id:2, name:"item2"}]
let r=arr1.filter(x=> arr2.some(y=>y.id==x.itemId));
console.log(r);

Reactjs trying to merge arrays

Let's say I have two array's
let array1 = ["H","E","", "","O","","","R","L","D"];
let array2 = ["","","L","L","","W","O","","",""];
I want to merge them such that they would then contain:
array3 = ["H","E","L", "L","O","W","O","R","L","D"];
How would I achieve this?
To be more clear I have a target array which is array3 an empty array and then I'm generating random characters and if they match array3 adding them to the blank array in the specific position with react state. It is just not storing the position and character each time but just changing it. SO my idea is to set the state such that I merge the current state with the new characters that are found.
TLDR:- Brute forcing Hello World meme.
You can use Array.prototype.map() to create a new array array3 out of iterating over array1 and get the l (letters) and if any l evaluates to falsey then get the letter at the same i (index) in the array2.
Note that instead of declaring your arrays with let you should always use const because it makes code easier to read within its scope, and const variable always refers to the same object.
Code example:
const array1 = ["H","E","", "","O","","","R","L","D"];
const array2 = ["","","L","L","","W","O","","",""];
const array3 = array1.map((l, i) => l || array2[i]);
console.log(array3);
Try it:
let arr1 = ["H","E","", "","O","","","R","L","D"];
let arr2 = ["","","L","L","","W","O","","",""];
let arr3 = [];
arr1.forEach((val, index) => {
if (val === '') {
arr3[index] = arr2[index];
} else {
arr3[index] = val;
}
});
console.log(arr3);

What is the javascript equivalent of numpy argsort?

I want to sort the imgUrl array by click count. I have two arrays.
clickCount = [5,2,4,3,1]
imgUrl = ['1.jpg','2.jpg','3.jpg','4.jpg','5.jpg']
In numpy it is easy. I use order = np.argsort(clickCount) then I create another array newArray = [imgUrl[i] for i in order].
How do I achieve the same effect in javascript (preferably vanilla)?
You can use a Schwartzian transform also known as Decorate-Sort-Undecorate (DSU) in python.
DSU:
Decorate - Use Array#Map to enrich each item in the array with the needed sort data
Sort - sort using the added data
Undecorate - extract the sorted data using Array#map again
Demo:
const dsu = (arr1, arr2) => arr1
.map((item, index) => [arr2[index], item]) // add the args to sort by
.sort(([arg1], [arg2]) => arg2 - arg1) // sort by the args
.map(([, item]) => item); // extract the sorted items
const clickCount = [5,2,4,3,1];
const imgUrl = ['1.jpg','2.jpg','3.jpg','4.jpg','5.jpg'];
const result = dsu(imgUrl, clickCount);
console.log(result);
thanks to dankal444 for the refactor to the function
For completeness, here's my solution to the actual answer (providing argsort function), by expanding on Ori's answer with DSU.
Since sort is by default taking the first element, so implementing it as DSU is merely adding an index, sorting it, then taking the indices.
let decor = (v, i) => [v, i]; // set index to value
let undecor = a => a[1]; // leave only index
let argsort = arr => arr.map(decor).sort().map(undecor);
clickCount = [5, 2, 4, 3, 1]
imgUrl = ['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg']
order = argsort(clickCount);
newArray = order.map(i => imgUrl[i])
console.log(newArray);
Functional approach (like #Ori Drori's code) is always a charm to watch, but in this case, you only need to re-arrange an array's items. I believe that there is a simpler way to go and is a much easier code to read.
const clickCount = [5,2,4,3,1];
const imgUrl = ['1.jpg','2.jpg','3.jpg','4.jpg','5.jpg'];
sortByArrayRefOrder = (data, orderRefArr) => {
let orderedArr = [], i=0;
orderRefArr.map( o => { orderedArr[o-1] = data[i++]});
return orderedArr.reverse();
}
console.log ( sortByArrayRefOrder(imgUrl, clickCount) );

How to get the difference between two arrays?

I have 2 arrays:
arr1 = [[11,12],[11,13],[11,14], [12,13]];
arr2 = [[11,13],[11,14]];
Expected result [[11,12],[12,13]].
How can I get the difference between the two arrays? I use lodash _.difference but it gives me a wrong answer.
You need to use _.differenceWith(), because you need to compare the elements of the sub-arrays. By default, it just tests whether the sub-arrays are the same objects, which they presumably aren't.
result = _.differenceWith(arr1, arr2, _.isEqual);
Using just javascript, and only for this and similar examples
var a1 = [[11,12],[11,13],[11,14], [12,13]];
var a2 = [[11,13],[14,11]];
var a3 = a1.filter(ar1 => !a2.some(ar2 => ar1.every(n1 => ar2.includes(n1))))
console.log(a3); // [[11,12],[12,13]]
There are too many criteria to create a generic solution.
For example is [11,12] the same as [12,11], maybe only references to the same array are the same, (ar1 === ar2) as true. What if there are two identical entries in the same array and one in the other, do you filter one out, or keep it? The number of questions can go on for some time and it gets worse the deeper the nesting and the greater the number of types stored in the array.
var a1 = [[11,12],[11,13],[11,14], [12,13]]
var a2 = [[11,13],[14,11],[12,14]];
a3 = [];
[[a1,a2],[a2,a1]].forEach(a=>{
a3.push(...a[0].filter(
ar1 => !a[1].some(
ar2 => ar1.every(
n1 => ar2.includes(n1)
)
)
))
});
console.log("[["+a3.join("], [")+"]]")
Just a few lines of pure JS is sufficient for this separation (union') job. Besides you should make sure to check both arrays over the other.
var arr1 = [[11,12],[11,13],[11,14],[12,13]],
arr2 = [[11,13],[11,14],[12,14]];
res = arr1.reduceRight((p,c,i,a) => { var fi = p.findIndex(s => c.every(n => s.includes(n)));
return fi !== -1 ? (a.splice(i,1),
p.splice(fi,1),
p)
: p;
},arr2)
.concat(arr1);
console.log(res);
You could do it without lodash. The tip woud be to map subarrays into strings to make comparison easy
var arr1 = [[11,12],[11,13],[11,14], [12,13]];
var arr2 = [[11,13],[11,14],[12,14]];
var res = arr1.concat(arr2).map(x => x.join(",")).filter((x,i,arr) => arr.indexOf(x) === arr.lastIndexOf(x)).map(x => x.split(","));
console.log(res);

Categories

Resources