match two Arrays and keep order of both equal - javascript

So I have two arrays with the same length, but not entirely the same data as follows:
Array1: [{name: john, num: 030}, {name: david, num: 130}, {name: john, num: 200}, {name: jane, num: 500}]
Array2: [{name: john, num: 030}, {name: david, num: 130}, {name: jane, num: 500}, {name: '', num: ''}]
Array2 only has element where num matches Array1 num
Is there a way to make sure that these two arrays match their indexes even if the data does not match
for example, their index will look like this
Array1: [{name: john, num: 030}, {name: david, num: 130}, {name: john, num: 200}, {name: jane, num: 500}]
Array2: [{name: james, num: 030}, {name: frank, num: 130}, {name: '', num: ''}, {name: kate, num: 500},]
This means they match by index, and order is maintained.
The main goal is that Array2 maintains the order of Array1.

According to the description seen in the question, list two logics
The value of attribute num is unique in each array
The only exception is an empty string
I implemented it according to the above logic, you can see if it helps you, if the logic does not meet your actual needs, you can provide more details and clear logic, I will adjust it
const array1 = [{name: 'john', num: '030'}, {name: 'david', num: '130'}, {name: 'john', num: '200'}, {name: 'jane', num: '500'}];
let array2 = [{name: 'david', num: '130'}, {name: 'jane', num: '500'}, {name: 'john', num: '030'}, {name: '', num: ''}];
const originalLength = array2.length;
const originalArr = array2.slice(0, originalLength);
array2.length = originalLength * 2;
const provide = (arr, field, index) => {
let result = arr.filter(a => a[field] == array1[index][field]);
if(result.length == 0){
result = arr.filter(a => a[field] == '');
}
return result[0];
};
for(let i=0; i<array1.length ; i++)
{
const item = provide(originalArr, 'num', i);
array2[i] = item;
}
array2.length = originalLength;
console.log(JSON.stringify(array2));

Related

how to filter multiple values from an array in javascript

I have an array of json elements. and I want to filter the array based on the specific values. below is the array.
var arr = [
{name: bobby, id: 1, age: 23},
{name: charls, id: 2, age: 28},
{name: indi, id: 3, age: 23},
{name: charlie, id: 4, age: 25}]
from the above array I want to filter only staff whose names are bobby && indi. I have tried below code.
var filteredArray;
for (var i =0 ; i < arr.length; i++){
if(arr[i].name === 'bobby' || arr[i].name === 'indi'){
filteredArray.push(arr[i]);
}
}
but through the above code, I need to mention OR(||) conditions too many times and these number of names can change like 1 time I want only staff with Bobby name and other time I want Bobby, Indi and Charlie. is there a way to make it dynamic. if yes, please let me know. Thanks in advance.
You can store names that needs to be filters in an array and then check if name exists in array or not
eg.
var arr = [
{name: "bobby", id: 1, age: 23},
{name: "charls", id: 2, age: 28},
{name: "indi", id: 3, age: 23},
{name: "charlie", id: 4, age: 25}
]
const names = ["bobby", "indi"];
const filtered = arr.filter((item)=>{
return names.includes(item.name)
});
console.log(filtered)
For older(eg. IE11) browsers -
var arr = [
{name: "bobby", id: 1, age: 23},
{name: "charls", id: 2, age: 28},
{name: "indi", id: 3, age: 23},
{name: "charlie", id: 4, age: 25}
]
const names = ["bobby", "indi"];
const filtered = [];
for(var i =0; i<arr.length - 1; i++){
if(names.indexOf(arr[i].name) > -1){
filtered.push(arr[i])
}
}
console.log(filtered)
You can use Array.includes() to filter items as followings:
var arr = [
{name: 'bobby', id: 1, age: 23},
{name: 'charls', id: 2, age: 28},
{name: 'indi', id: 3, age: 23},
{name: 'charlie', id: 4, age: 25}
]
const keywords = ['bobby', 'indi'] // You can add keywords to be filtered to this array to make it dynamic
const filtered = arr.filter(item => keywords.includes(item.name))
console.log(filtered)
You could create an array of names you want to filter and then:
if you want to stick to pre-ES6 coding:
var arr = [{
name: 'bobby',
id: 1,
age: 23
},
{
name: 'charls',
id: 2,
age: 28
},
{
name: 'indi',
id: 3,
age: 23
},
{
name: 'charlie',
id: 4,
age: 25
}
];
var names = ['bobby', 'indi'];
var filteredArray = [];
for (var i = 0; i < arr.length; i++) {
if (names.indexOf(arr[i].name) > -1) filteredArray.push(arr[i]);
}
console.log(filteredArray);
or, if you are willing to switch to ES6+ coding:
const arr = [{
name: 'bobby',
id: 1,
age: 23
},
{
name: 'charls',
id: 2,
age: 28
},
{
name: 'indi',
id: 3,
age: 23
},
{
name: 'charlie',
id: 4,
age: 25
}
];
const names = ['bobby', 'indi'];
const filteredArray = arr.filter(item => names.includes(item.name));
console.log(filteredArray);

Filter array of objects by amount property

I need to get the expectedOutput array, which consists of the objects with the higher amount number. Thanks in advance.
let arr1 = [{name: 'Almendras', amount: 0},{name: 'Nueces', amount: 0}, {name: 'Chocolate', amount: 0}];
let arr2 = [{name: 'Almendras', amount: 2}];
let expectedOutput = [{name: 'Almendras', amount: 2}, {name: 'Nueces', amount: 0}, {name: 'Chocolate', amount: 0}];
Im tried by this way:
console.log(arr2.filter(x => x.amount > arr1[x].amount));
Since the example you gave uses the same index in both arrays, you could map through the first array and index compare the second array and return one or the other:
var res = arr1.map((v, index) => v.amount > arr2[index].amount ? v : arr2[index]);
If either array can be larger than the other you could find the larger array, loop through it and compare it with the smaller one and add the objects to a new array until you reach the end, and then add the remaining objects from the larger array.
You can use Array#map, which provides the index as the second argument to the callback, and use a ternary operator the compare the element at the index in both arrays.
let arr1 = [{name: 'Almendras', amount: 0},{name: 'Nueces', amount: 0}, {name: 'Chocolate', amount: 0}];
let arr2 = [{name: 'Almendras', amount: 2}, {name: 'Nueces', amount: 0}, {name: 'Chocolate', amount: 1}];
let res = arr1.map((curr,idx)=>curr.amount > arr2[idx].amount?curr:arr2[idx]);
console.log(res);
If you know that both arrays are sorted according to the inner object name key, then the other answers which compare indices are probably the best method. However, if you know that the arrays could be unsorted, here is a potential solution.
Note: If you are dealing with arrays of varying sizes, you would have to filter or iterate through both arrays.
let arr1 = [{name: 'Almendras', amount: 0}, {name: 'Nueces', amount: 0}, {name: 'Chocolate', amount: 0}];
let arr2 = [{name: 'Almendras', amount: 2}, {name: 'Chocolate', amount: 1}, {name: 'Nueces', amount: 0}];
let expectedOutput = [{name: 'Almendras', amount: 2}, {name: 'Nueces', amount: 0}, {name: 'Chocolate', amount: 1}];
let actualOutput = arr1.map((ele1) => {
let ele2 = arr2.find((e) => e.name === ele1.name);
if(ele2) {
if(ele2.amount >= ele1.amount) {
return ele2;
}
}
return ele1;
});
console.log("actual: ", actualOutput);
console.log("expected: ", expectedOutput);

UnderscoreJS: trim array of objects based on condition

I have an array of JSON object as shown below:
var data = [
{name: '', age: 12},
{name: 'bcd', age: 15},
{name: 'cdf', age: 13},
{name: '', age: 11},
{name: 'fgh', age: 8},
{name: '', age: 10},
];
using underscore I want to trim this object in such a way that it should return:
[{name: 'bcd', age: 15},
{name: 'cdf', age: 13},
{name: '', age: 11},
{name: 'fgh', age: 8}]
I tried with below code:
var firstIndex = _.indexOf(data, _.find(data, function(d){ return d.name !== ''; }));
var lastIndex = _.indexOf(data, _.find(data.slice().reverse(), function(d){ return d.name !== ''; }));
console.log(data.slice(firstIndex, lastIndex + 1) );
But I think, there should be a better way than this.
Here is the JSFiddle
Edit:
I want all data from the top and bottom to be trimmed where name is blank. But not in middle of the array element.
Same as string.Trim() method. when I apply trim on " one two three " text, it will remove blank space from the starting and end but not the space between words.
your logic is fine, just use _.findLastIndex() instead of using _.findIndex() on the reversed array:
const data = [
{name: '', age: 7},
{name: '', age: 12},
{name: 'bcd', age: 15},
{name: 'cdf', age: 13},
{name: '', age: 11},
{name: 'fgh', age: 8},
{name: '', age: 10},
{name: '', age: 12},
{name: '', age: 14},
];
function trimArray(predicate, arr) {
const start = _.findIndex(arr, predicate);
const end = _.findLastIndex(arr, predicate);
return arr.slice(start, end + 1);
}
const result = trimArray((o) => o.name !== '', data);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Looks like you want to return the array without first and last item, then use slice
var trimmedData = data.slice( 1, data.length - 1 );
I want all data from the top and bottom to be trimmed where name is
blank. But not in middle of the array element.
Define a trimLeftFn
var trimLeftFn = arr => {
var hasValue = false;
arr = arr.filter( s => {
hasValue = hasValue || s.name.length > 0;
return hasValue;
});
return arr;
};
var trimmedData = trimLeftFn( trimLeftFn (data ).reverse() ).reverse();
Demo
var data = [
{name: '', age: 12},
{name: 'bcd', age: 15},
{name: 'cdf', age: 13},
{name: '', age: 11},
{name: 'fgh', age: 8},
{name: '', age: 10},
];
var trimLeftFn = arr => {
var hasValue = false;
arr = arr.filter(s => {
hasValue = hasValue || s.name.length > 0;
return hasValue;
});
return arr;
};
var trimmedData = trimLeftFn(trimLeftFn(data).reverse()).reverse();
console.log(trimmedData);

Lodash, taking objects fulfilling requirements

Example:
Animals = [{Name: 'Dog', Id: 0},
{Name: 'Cat', Id: 1},
{Name: 'Mouse', Id: null}]
How to take all objects where Id isn't null into new array?
Expected output:
NewArray = [{Name: 'Dog', Id: 0},
{Name: 'Cat', Id: 1}]
Try with _.filter
var Animals = [{Name: 'Dog', Id: 0},{Name: 'Cat', Id: 1},{Name: 'Mouse', Id:null}]
var newArray =_.filter(Animals ,a=> a.Id != null)
console.log(newArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.2/lodash.min.js"></script>

How to create Generic Map/Zip Function that Transpose N Arrays

I have N Arrays. How can I create a generic Map/Zip function that can transpose N number of arrays together. Please see code below for example.
Also, how can i make it work for multidimensional arrays.
Thank you.
// A Arrays
const arrayA1 = [{name: "James"}, {name: "John"}, {name: "Jack"}]
const arrayA2 = [{age: 10}, {age: 20}, {age: 12}]
// B Arrays
const arrayB1 = [{name: "James"}, {name: "John"}, {name: "Jack"}]
const arrayB2 = [{age: 10}, {age: 20}, {age: 12}]
const arrayB3 = [{height: 150}, {height: 200}, {height: 180}]
const result = {}
const result1 = {}
// Transpose A Arrays Only (does not work for B Arrays)------ How can i make the SAME function work for both A and B arrays
arrayA1.map((x, y) => {
let abc = [x, arrayA2[y]];
result1[y] = abc;
result[x.name] = arrayA2[y]
})
console.log(result);
// { James: { age: 10 }, John: { age: 20 }, Jack: { age: 12 } }
// WHICH IS BETTER IMPLEMENTATION >>>>>> result or result1 >> I intend to send to mongodb
console.log(result1);
/*
{ '0': [ { name: 'James' }, { age: 10 } ],
'1': [ { name: 'John' }, { age: 20 } ],
'2': [ { name: 'Jack' }, { age: 12 } ] }
*/
A better result structure would be an array of objects, like
[
{name: xxx, age: yyy},
{name: xxx, age: yyy},
{name: xxx, age: yyy}
]
Here's code to generate it:
// A Arrays
const arrayA1 = [{name: "James"}, {name: "John"}, {name: "Jack"}]
const arrayA2 = [{age: 10}, {age: 20}, {age: 12}]
// B Arrays
const arrayB1 = [{name: "James"}, {name: "John"}, {name: "Jack"}]
const arrayB2 = [{age: 10}, {age: 20}, {age: 12}]
const arrayB3 = [{height: 150}, {height: 200}, {height: 180}]
//
zip = (...arrays) => arrays[0].map((_, n) => arrays.map(a => a[n]));
merge = (x, y) => Object.assign(x, y);
zipMerge = (...arrays) => zip(...arrays).map(props => props.reduce(merge, {}))
//
console.log(zipMerge(arrayA1, arrayA2))
console.log(zipMerge(arrayB1, arrayB2, arrayB3))

Categories

Resources