Comparing elements one array with another of different lengths - javascript

Consider an array1 of n no. of features
array1=[feat1,feat2,...,featn]
and array2 of m no. of linearRings
array2=[ring1,ring2,...,ringm].
Now write a program in javascript such that every element of array2 is compared with every element of array1.
PS: please suggest an approach apart from nested for loop.
The approach I tried:
features.map(feature => {
linearRings.map(linearRing => {
const singleFeature = getTurfFeature(feature);
const pointOfLinearRing = point(
transform(linearRing.getFirstCoordinate(), 'EPSG:3857', 'EPSG:4326')
);
const checkForOverlap = booleanIntersects(pointOfLinearRing, singleFeature);
checkForOverlap && feature.getGeometry().appendLinearRing(linearRing);
});
});

You can use Set & store the value of the first array here. Then you can check the result of point function and verify if it is present in set
const array1 = ['feat1', 'feat2', 'featn']
const set = new Set();
const array2 = ['ring1', 'ring2', 'ringm'];
array1.forEach(feature => {
const singleFeature = getTurfFeature(feature);
if (!set.has(singleFeature)) {
set.add(singleFeature)
}
})
array2.map(linearRing => {
const pointOfLinearRing = point(
transform(linearRing.getFirstCoordinate(), 'EPSG:3857', 'EPSG:4326')
);
// do whatever you want to do here
return set.has(pointOfLinearRing);
});

Related

Sort array elements on JavaScript

I have an array, each subarray of which contains different positions in different order:
[
["apple(2)", "banana(5)"],
["peach(3)", "banana(1)"],
["apple(1)"]
]
I need to sort it on JavaScript (ES6) and i expect to get an array like this:
[
["apple(2)", "banana(5)", "peach(0)"],
["apple(0)", "banana(1)", "peach(3)"],
["apple(1)", "banana(0)", "peach(0)"]
]
Order of each subarray should be the same. If subarray don't have some position, i need to add it with 0 value. Can i using something like map() or sort() function or need to compare it manually?
Here is functional programming approach, using a Map and reduce:
const data = [['apple(2)', 'banana(5)'],['peach(3)', 'banana(1)'],['apple(1)'],];
// Create a Map with default values for each name, i.e. with "(0)":
let names = new Map(data.flat().map(item => [item.replace(/\d+/, ""), item.replace(/\d+/, "0")]));
let result = data.map(row =>
[...row.reduce((map, item) =>
map.set(item.replace(/\d+/, ""), item), // Overwrite default
new Map(names) // Start with clone of original Map
).values()]
);
console.log(result);
You have to loop over to get the keys used. You then have to loop over a second time to get the fill in the missing keys. There are many ways of doing it, this is one.
var data = [
["apple(2)", "banana(5)"],
["peach(3)", "banana(1)"],
["apple(1)"]
];
// match string and number
var re = /([^(]+)\((\d+)\)/;
// Loop over and find all of the keys
var grouped = data.reduce((info, subset, index) => {
subset.forEach(item => {
// find the key and count
var parts = item.match(re);
// have we seen this key?
if (!info[parts[1]]) {
// if not create an array
info[parts[1]] = Array(data.length).fill(0);
}
// set the key index with the count
info[parts[1]][index] = parts[2];
})
return info;
}, {});
// loop over the groups and fill in the set
Object.entries(grouped).forEach(([key, counts], colIndex) => {
counts
.forEach((cnt, rowIndex) => {
data[rowIndex][colIndex] = `${key}(${cnt})`;
})
});
console.log(data);
First get the unique words. Then traverse array of arrays to check if the word is present or not. If it is not present then make the word according to your condition and if present then put the original word to the tmp array. At last sort it for each iteration. By the way, I used regex replace method to get the word.
const data = [
['apple(2)', 'banana(5)'],
['peach(3)', 'banana(1)'],
['apple(1)'],
];
const words = [...new Set(data.flat().map((x) => x.replace(/[^a-z]/gi, '')))];
const ret = data.map((x) => {
const tmp = [];
const newX = x.map((y) => y.replace(/[^a-z]/gi, ''));
for (let i = 0, l = words.length; i < l; i += 1) {
if (newX.includes(words[i])) tmp.push(x.shift());
else tmp.push(`${words[i]}(0)`);
}
return tmp.sort();
});
console.log(ret);

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);

Looping over two arrays in javascript simultaneously

let masterList=[{id:1,name:'Abc'},{id:2,name:'Def'},{id:3,name:'Ghi'}];
let selectedList=[2,3];
The desired result is to have
//desiredList=[{id:2,name:'Def'},{id:3,name:'Ghi'}]
Currently what I am doing is
let parsedArray = [];
masterList.forEach(mItem => {
selectedList.forEach(sItem => {
if (mItem.id === sItem) {
parsedArray.push(mItem);
}
});
});
desiredList=parsedArray
I do not find this method efficient when iterating over large arrays, is there any logic, any inbuilt javascript operators using which I can achieve the same?
You could take a map with id as key and the object as value and map the wanted values from the map by mapping selectedList.
This approach uses the order from selectedList.
var masterList = [{ id: 1, name: 'Abc' }, { id: 2, name: 'Def' }, { id: 3, name: 'Ghi' }],
selectedList = [2, 3],
result = selectedList.map(Map.prototype.get, new Map(masterList.map(o => [o.id, o])));
console.log(result);
It should be a simple filter on the masterList:
masterList.filter(item => selectedList.includes(item.id));
You can use Array filter() to do this.
Demo:
let masterList=[{id:1,name:'Abc'},{id:2,name:'Def'},{id:3,name:'Ghi'}];
let selectedList=[2,3];
let desiredList = masterList.filter((val) => selectedList.includes(val.id));
console.log(desiredList)
You can first convert selectedList to Set and then use filter() method array of objects.
You can use Set.prototype.has to check whether the id of the objects exists in the set or not. And this method has O(1) time-complexity. So the time-complexity of the whole algorithm will be linear.
let masterList=[{id:1,name:'Abc'},{id:2,name:'Def'},{id:3,name:'Ghi'}];
let selectedList = [2,3];
let set = new Set(selectedList);
let res = masterList.filter(x => set.has(x.id));
console.log(res)
Turn the first array into an object indexed by id first, so you can look up the appropriate matching object in O(1) time, and then you can .map the selectedList:
const masterList=[{id:1,name:'Abc'},{id:2,name:'Def'},{id:3,name:'Ghi'}];
const selectedList=[2,3];
const masterById = masterList.reduce((a, obj) => {
a[obj.id] = obj;
return a;
}, {});
const desiredList = selectedList.map(id => masterById[id]);
console.log(desiredList);
Try this:
let masterList=[{id:1,name:'Abc'},{id:2,name:'Def'},{id:3,name:'Ghi'}];
let selectedList=[2,3];
const result = masterList.filter(({id})=> selectedList.includes(id));
console.log(result);

ES6 Merge two arrays (array contains another array inside) based on key Typescript or Javascript

I want to merge two arrays both array contains another array inside. refer below two arrays.
const arr1=
[{"projectId":30278,"projectName":null,"details":[{"amount":"9097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"}]},{"projectId":37602,"projectName":null,"details":[{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"}]}]
const arr2=
[{"projectId":30278,"projectName":null,"details":[{"amount":"8097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"}]},{"projectId":37602,"projectName":null,"details":[{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"}]}]
when i used ES6 spread operator, both values are appended to single array. But I want to merge based upon prjectId in that array.
So after merge, i need to get the result like below
const result =
[{"projectId":30278,"projectName":null,"details":[{"amount":"9097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"},
{"amount":"8097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"}
]},
{"projectId":37602,"projectName":null,"details":[{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"},
{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"}
]}]
const arr1=
[{"projectId":30278,"projectName":null,"details":[{"amount":"9097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"}]},{"projectId":37602,"projectName":null,"details":[{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"}]}]
const arr2=
[{"projectId":30278,"projectName":null,"details":[{"amount":"8097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"}]},{"projectId":37602,"projectName":null,"details":[{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"}]}]
var fullArray = [...arr1,...arr2];
var mergedData ={};
fullArray.forEach(function(data){
if(mergedData[data.projectId]){
mergedData[data.projectId]["details"] = mergedData[data.projectId]["details"].concat(data.details)
} else {
mergedData[data.projectId] = data;
}
})
console.log(Object.values(mergedData))
You can easily achieve that using Lodash unionBy function.
const result = _.unionBy(arr1, arr2, 'projectId')
You can also try this in this case scenario.
let mergedArr = [];
let projectIdsArr1 = arr1.map(item => item.projectId);
arr2.map(outerLoopItem => {
if (projectIdsArr1.includes(outerLoopItem.projectId)) {
let found = arr1.find(innerLoopItem => innerLoopItem.projectId === outerLoopItem.projectId);
found.details = [...found.details, ...outerLoopItem.details];
mergedArr.push(found);
} else mergedArr.push(outerLoopItem);
});
console.log(mergedArr);

Array 'map' vs 'forEach' - functional programming

I have an array of objects:
let reports = [{ inbound_calls: [...], outbound_calls: [...], outbound_national_calls: [...] },...];
What is the best way to create a new array and assign into a variable:
1st approach - one loop:
let inbound_calls = []; outbound_national_calls = [], outbound_calls = [];
reports.forEach((e) => {
inbound_calls.push(e.inbound_calls);
outbound_national_calls.push(e.outbound_national_calls);
outbound_calls.push(e.outbound_calls);
})
2nd approach:
let inbound_calls = this.reports.map((report) => report.inbound_calls)
let outbound_national_calls = this.reports.map((report) => report.outbound_national_calls)
let outbound_calls = this.reports.map((report) => report.outbound_calls)
I'm starting to learn functional programming, and want to apply it to my code, I would go with first approach (one loop), but as I did research about functional programming I think the second one is the right way (much cleaner) but, I'm not sure, what is less expensive operation?
If your ultimate goal is to create three variables out of the object, you may use object destructuring as follows. No loops required.
let reports = {
inbound_calls: [1, 2, 3],
outbound_calls: [4, 5, 6],
outbound_national_calls: [7, 8, 9]
};
let {inbound_calls, outbound_calls, outbound_national_calls} = reports;
console.log(inbound_calls);
console.log(outbound_calls);
console.log(outbound_national_calls);
If you want to copy the arrays, just use Array#slice (the 0 passed is optional as it is the default start index so you can omit it if you want) like:
let inbound_calls = reports.inbound_calls.slice(0),
outbound_national_calls = reports.outbound_national_calls.slice(0),
outbound_calls = reports.outbound_calls.slice(0);
or Array.from like:
let inbound_calls = Array.from(reports.inbound_calls),
outbound_national_calls = Array.from(reports.outbound_national_calls),
outbound_calls = Array.from(reports.outbound_calls);
What you're essentially doing is a matrix transposition:
const report = (inbound_calls, outbound_calls, outbound_national_calls) =>
({ inbound_calls, outbound_calls, outbound_national_calls });
const reports = [report(1,2,3), report(4,5,6), report(7,8,9)];
const transpose = reports =>
report( reports.map(report => report.inbound_calls)
, reports.map(report => report.outbound_calls)
, reports.map(report => report.outbound_national_calls) );
console.log(transpose(reports));
Now, depending upon your application the fastest way to transpose a matrix might be not to transpose it at all. For example, suppose you have a matrix A and its transpose B. Then, it holds that for all indices i and j, A[i][j] = B[j][i]. Consider:
const report = (inbound_calls, outbound_calls, outbound_national_calls) =>
({ inbound_calls, outbound_calls, outbound_national_calls });
const reports = [report(1,2,3), report(4,5,6), report(7,8,9)];
// This is equivalent to transpose(reports).outbound_calls[1]
const result = reports[1].outbound_calls;
console.log(result);
That being said, your second approach is IMHO the most readable.

Categories

Resources