Remove out nested array based on another array - javascript

I have this nested array
let arr = [['first', 'second'], ['third', 'fourth'], ['second', 'third']]
now I want to filter/remove based on exactly this array.
let filter = ['first', 'second']
and now my expected output should be:
[['third', 'fourth'], ['second', 'third']]
I only have this piece of code:
arr.filter(str => str.indexOf('second') === -1)
Which doesn't give the expected output, it also removed ['second', 'third'] because it filters whatever element that contains 'second'.. so they must be a better way or an improvement to the code.

If you care about ordering and need exact matches, you can write a simple arrays equal method and then filter out any equal arrays:
const arrEq = (a, b) => a.length === b.length && a.every((e, i) => b[i] === e);
const arr = [['first', 'second'], ['third', 'fourth'], ['second', 'third']];
const filter = ['first', 'second'];
console.log(arr.filter(e => !arrEq(e, filter)));
If you want the same elements but order doesn't matter:
const arrItemsEq = (a, b, cmp) => {
if (a.length !== b.length) {
return false;
}
a = a.slice().sort(cmp);
b = b.slice().sort(cmp);
return a.every((e, i) => e === b[i]);
};
const arr = [["a", "b"], ["b", "c"]];
const filter = ["b", "a"];
const strCmp = (x, y) => x.localeCompare(y);
console.log(arr.filter(e => !arrItemsEq(e, filter, strCmp)));
If you want to filter out arr elements if they don't include at least one of each filter element:
const arr = [["a", "b"], ["b", "c"]];
const filter = ["b", "a"];
console.log(arr.filter(x => !filter.every(y => x.includes(y))));

You need to test two arrays for equality. [There are many ways to do it] but once you pick one, you can simply remove any array that is equal to another. To avoid reimplementing the wheel, I'll use the LoDash _.isEqual for demonstration purposes:
let arr = [['first', 'second'], ['third', 'fourth']]
let filter = ['first', 'second']
let result = arr.filter(item => !_.isEqual(filter, item));
console.log(result);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
The equality function can be swapped to any implementation that satisfies you. A very simple one is simply:
function isEqual(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
}
but it's not guaranteed to be correct (e.g, isEqual([1, 2], ["1,2"]) //true) and it's going to be slow with large inputs. But it might still work, depending on circumstances.

You can use filter to check if the element doesn't include every string of the filter array.
let arr = [['first', 'second'], ['third', 'fourth'], ['second', 'third']]
let filterout = ['first', 'second']
let arr2 = arr.filter(x => ! filterout.every(y => x.includes(y)))
console.log(arr2)
But by using filter it basically creates a new array with fewer elements. Which is good enough for a small array.
If if the goal is to directly change the original array, then those elements can be spliced from that array.
let arr = [ ['first', 'second'], ['third', 'fourth'], ['second', 'third'], ['second', 'first'] ]
let filterout = ['first', 'second']
// getting the indexes of the element that need to be removed
let idxArr = []
arr.forEach( (x, idx) => { if(x.every(y => filterout.includes(y))) idxArr.push(idx)})
// removing the elements from the array
idxArr.sort((i,j)=>j-i).forEach(idx => {arr.splice(idx, 1)})
console.log(arr)

Related

Find second largest elements in array with duplicates in javascript

Am having array to find second largest elements including repeated value pls find below example.
const arr= [1,2,5,5,6]
expected result should be
[5,5]
I tried with map and math.max but i stuck up on logical issue.kindly help me
Below snippet could help you
const arr = [1, 2, 5, 5, 6]
const max = Math.max(...arr)
const newArr = arr.filter(element => element !== max)
const newMax = Math.max(...newArr)
const secondLargest = arr.filter(element => element === newMax)
console.log(secondLargest)
Here is a simpler approach, However it may not be the best approach in terms of performance for large data
const ar= [1,2,5,5,6]
secmax = Math.max(...ar.filter((n,i) => Math.max(...ar) !=n ))
res = ar.filter(n =>n == secmax)
console.log(res)
Using a Set to extract unique values shortens the code quite a bit
var arr = [1,5,2,5,4,8];
var uniqueValues = [...new Set(arr)].sort((a, b) => b-a);
var secondHighest = uniqueValues[1]; // 0 is max, 1 is second highest, etc.
var result = arr.filter(x => x === secondHighest);
Please keep in mind that there should be some due diligence in accessing the results (what happens if the code is fed with empty arrays, or arrays with a single repeated value? There are many cases not covered here)
You could group the values and sort the array of arrays and get the second array.
const
array = [1, 2, 5, 5, 6],
result = Object
.values(array.reduce((r, v) => (r[v] = [...(r[v] || []), v], r), {}))
.sort(([a], [b]) => b - a)
[1];
console.log(result);

Search nested array in lodash/es6

Looking to search a value in an array of array and returning index. Most of the answers are array of objects. So I am looking to search for eg 22 and get 2 as the index where the value was found
Here is the code pen
https://codesandbox.io/s/lodash-playground-array-pzzhe
const arr = [["a","b"],["f","r"],["r",22,"t"]];
console.log("arr", arr);
You could take plain Javascript with Array#findIndex with Array#includes.
var array = [["a", "b"], ["f", "r"], ["r", 22, "t"]],
value = 22,
index = array.findIndex(a => a.includes(value));
console.log(index);
Option 1 Use findIndex
const arr = [["a","b"],["f","r"],["r",22,"t"]];
console.log(arr.findIndex(a => a.includes(22)));
Option 2: Use functions indexOf and includes:
const arr = [["a","b"],["f","r"],["r",22,"t"]];
// find element
const element = arr.find(a => a.includes(22));
// find element index
const currentIndex = arr.indexOf(element)
console.log(currentIndex);
indexOfFlat = (val, array) => array.findIndex(_arr => _arr.includes(val));
const arr = [["a","b"],["f","r"],["r",22,"t"]];
console.log("arr", arr);
console.log("index", indexOfFlat(22, arr))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.core.min.js"></script>
In case you would actually need the sub-array in which the value was found, you could also use Array.find and its index and get both:
const arr = [["a","b"],["f","r"],["r",22,"t"]];
let index, subArr = arr.find((x,i) => x.includes(22) && ~(index=i))
console.log('sub-array: ', subArr)
console.log('index: ', index)

How to compare two arrays or strings in javascript?

I have a array1 from checkboxes selected, and i need to compare with the most similar, how i do that?
var array1 = ["pain", "fever", "vomit"]
var array2 = ["diarrhea", "fever", "vomit", "embolism", "bleeding"]
var array3 = ["diarrhea", "tumor", "vomit", "cold", "bleeding"]
I tried some methods but they only return me as "true" or "false", I would like to get the most similar array1
You could count the number of similar elements using reduce, then order your arrays by similarity and take the first element:
const array1 = ["pain", "fever", "vomit"];
const array2 = ["diarrhea", "fever", "vomit", "embolism", "bleeding"];
const array3 = ["diarrhea", "tumor", "vomit", "cold", "bleeding"];
const countSimilarElements = (arr1, arr2) => arr1.reduce((count, x) => count + arr2.includes(x), 0);
const orderBySimilarity = (arr1, ...arr) =>
arr.map(x => ({ array: x, similarity: countSimilarElements(arr1, x) }))
.sort((a, b) => b.similarity - a.similarity);
const ordered = orderBySimilarity(array1, array2, array3);
console.log(ordered);
console.log(ordered[0].array);
This function takes in a the array you want to compare as the 'base' and a list of other arrays as 'arr_list', then returns a similarity array showing how similar each array in 'arr_list' was to the 'base'. This way you can compare multiple arrays with a single call and know reference their similarity by referencing the index of the returned similarity array.
const a = ['11', '22', '33'], b = ['11', '44', '55', '66'], c = ['55', '33', '11', '22'], d = ['11', '66', '44', '22'];
const Similarity = (base, arr_list) => {
let similarity = new Array(arr_list.length).fill(0);//creates similarity array which defaults to 0
base.forEach( el => {
arr_list.forEach( (arr, i) => similarity[i] += arr.includes(el) )
});
return similarity;
}
const similarity = Similarity(a, [b,c,d])
console.log(similarity)

How to compare two arrays using lodash (the order matters)

var arr1=[3,4,5,6,7,1,9];
var arr2=[1,3,4,6,7,5,9];
I want to compare arr2 to arr1. But the methods difference() and intersection() only seem to find if the two arrays have the same elements or not. I want to compare the two arrays spot by spot like arr1[0] to arr2[0], arr1[1] to arr2[1]. And it should show:
intersection: 6,7,9
difference: 1,3,4,5
How can I achieve this?
You can do this in lodash by zipping both arrays, filtering, and than taking the last item of each pair. The comperator for intersection is that the pair is equal. The comperator for difference is that the pair are not equal.
const arr1 = [3,4,5,6,7,1,9];
const arr2 = [1,3,4,6,7,5,9];
const compare = (comperator) => (arr1, arr2) =>
_.zip(arr1, arr2)
.filter(comperator)
.map(_.last);
const eq = _.spread(_.eq);
const intersection = compare(eq);
const difference = compare(_.negate(eq));
console.log('intersection ', intersection(arr1, arr2));
console.log('difference ', difference(arr1, arr2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
You could iterate both arrays in parallel and sort them into two seperate Sets:
function* parallel(a, b) {
for(let i = 0; i < a.length || i < b.length; i++)
yield [ a[i], b[i] ];
}
const intersection = new Set,
difference = new Set;
for(const [a, b] of parallel(arr1, arr2)) {
if(a === b)
intersection.add(a);
else
difference.add(a).add(b);
}
console.log([...intersection], [...difference]);
This also could be solved with reduce:
var arr1 = [3, 4, 5, 6, 7, 1, 9];
var arr2 = [1, 3, 4, 6, 7, 5, 9];
const f = (a, b) => b.reduce((r,c,i) => (a[i] == c ?
r.intersection.push(c) :
r.difference.push(c), r), {intersection: [], difference: []})
console.log(f(arr1, arr2))
Where you start with a pre-set accumulator object and compare each array value using the index.
You could use xor from lodash and it will return an empty array if the arrays have the same elements.
const a1= ['a', 'b', 'd']
const a2= ['d', 'b', 'a']
_.xor(a1, a2).length;//0
Why don't you write your own utility function that checks equality of the sequence? Something like:
export function sequenceEqual<T>(firstSequence: T[], secondSequence: T[]): boolean {
if(!firstSequence || !secondSequence) return false;
return firstSequence.every(
(d, i) => d === secondSequence[i]
);
}
This way you can just return boolean. There is no need to perform an extra step to check if the code returned some array or number or whatever, what is length of the returned type, which number it is etc. You just ask are my sequences equal and get true or false.
One more benefit is that you are not dependent on some library. Unless they have sequenceEqual so that you don't have to write from scratch, just call it, but I couldn't find it yet in Lodash.

Getting elements of an array depending on corresponding values of another - Lodash

I have two JavaScript arrays:
var array1 = ['a','b','c','d'];
var array2 = [ 1, 0, 0, 1 ];
I want another array getting elements from array1 where the corresponding elements of array 2 in the same position match a condition. Both arrays must have the same elements.
For example:
I want elements of array1 where the corresponding elements of array2 are 0
Result = ['b','c']
Another example:
I want elements of array1 where corresponding elements of array2 are 1
Result = ['a','d']
I'm looking for a function on Lodash or Underscore Js Libraries to do this. I can implement it using vanilla javascript, but I'm curious to know if this can be done with these Libraries.
It's just the same as in plain Javascript.
filtered0 = array1.filter((_, i) => array2[i] === 0);
filtered1 = array1.filter((_, i) => array2[i] === 1);
var array1 = ['a','b','c','d'],
array2 = [ 1, 0, 0, 1 ];
console.log(_.filter(array1, (a, i) => array2[i] === 0));
console.log(_.filter(array1, (a, i) => array2[i] === 1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
This can be done elegantly by adding the following method to lodash:
_.mixin({'iter': xs => (w => () => w.next().value)(_(xs))})
Basically, it returns a function that iterates an array, that is, each invocation returns the next array element. With iter, your problem is easy:
var array1 = ['a','b','c','d'];
var array2 = [ 1, 0, 0, 1 ];
_.mixin({'iter': xs => (w => () => w.next().value)(_(xs))});
// positives
pos = _.filter(array1, _.iter(array2))
console.log(pos)
// negatives
neg = _.reject(array1, _.iter(array2))
console.log(neg)
// both
group = _.groupBy(array1, _.iter(array2))
console.log(group)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
You can zip(), filter(), and map(), like this:
_.chain()
.zip(array1, array2)
.filter(_.property(1))
.map(0)
.value();
You can get the zero values by negating the filter predicate, like this:
_.chain()
.zip(array1, array2)
.filter(_.negate(_.property(1)))
.map(0)
.value();
You can create custom function and use filter() but both arrays must be of same length.
var array1 = ['a', 'b', 'c', 'd'];
var array2 = [1, 0, 0, 1];
function filterBy(el) {
return array1.filter(function(e, i) {
return array2[i] == el;
})
}
console.log(filterBy(0))
console.log(filterBy(1))

Categories

Resources