I am trying to find out largest number from groups and assign them into an array of unique groups. I tried using map and lodash uniq but didnt help
Example
Lets say the main array consists of a typeid and a number seperated by colon (:)
I want to identify the largest number in from each typeid and they create an array out of it.
From the below example i am trying to generate an output like below
["abcdwidets:6564","nightly:6543"]
6564 & 6543 are the largest values in their respective groups
Code
var mainarray = ["abcdwidets:1234","abcdwidets:3432","abcdwidets:6564","nightly:3423","nightly:6543"]
var arr = [];
var needle;
var i = 0;
var flag = 0;
mainarray.forEach( (element) => {
arr = element.split(":");
arr = arr.map((val) => {
return val
});
})
Reduce the array into a Map, and get the highest number for each key (the string before the :). Then Array.map() the Map's entries iterator (by spreading) back to an array:
const mainarray = ["abcdwidets:1234","abcdwidets:3432","abcdwidets:6564","nightly:3423","nightly:6543"];
const result = [...mainarray.reduce((r, s) => {
const [k, v] = s.split(':');
if(!r.has(k) || r.get(k) < v) r.set(k, v);
return r;
}, new Map())]
.map(([k, v]) => `${k}:${v}`);
console.log(result);
U will need to split the mainArray into 2 arrays like this
arr1=['abcdwidets', 'nightly', ..., n];
arr2=[1628, 0378, 6144, ..., n];
Once u have splitted your main array into these 2 then you just do a bubble sort and turn these 2 into 1 again.
Related
so I want to find unique values from an array.
so for example I have this array:
const mainArr = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884']
so I want to find the first matching value for each unique item.
for example, in the array, I have two strings with the shape prefix, six items with the size prefix, and two items with the height prefix.
so I want to output to be something like
const requiredVal = ["shape-10983", "size-2364", "height-3399"]
I want only the first value from any set of different values.
the simplest solution will be to iterate on the list and storing what you got in a dictionary
function removeSimilars(input) {
let values = {};
for (let value of input) {//iterate on the array
let key = value.splitOnLast('-')[0];//get the prefix
if (!(key in values))//if we haven't encounter the prefix yet
values[key] = value;//store that the first encounter with the prefix is with 'value'
}
return Object.values(values);//return all the values of the map 'values'
}
a shorter version will be this:
function removeSimilars(input) {
let values = {};
for (let value of input)
values[value.splitOnLast('-')[0]] ??= value;
return Object.values(values);
}
You could split the string and get the type and use it aks key for an object along with the original string as value. At result take only the values from the object.
const
data = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884'],
result = Object.values(data.reduce((r, s) => {
const [type] = s.split('-', 1);
r[type] ??= s;
return r;
}, {}));
console.log(result);
If, as you mentioned in the comments, you have the list of prefixes already available, then all you have to do is iterate over those, to find each first element that starts with that prefix in your full list of possible values:
const prefixes = ['shape', 'size', 'height'];
const list = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884']
function reduceTheOptions(list = [], prefixes = [], uniques = []) {
prefixes.forEach(prefix =>
uniques.push(
list.find(e => e.startsWith(prefix))
)
);
return uniques;
}
console.log(reduceTheOptions(list, prefixes));
Try this:
function getRandomSet(arr, ...prefix)
{
// the final values are load into the array result variable
result = [];
const randomItem = (array) => array[Math.floor(Math.random() * array.length)];
prefix.forEach((pre) => {
result.push(randomItem(arr.filter((par) => String(par).startsWith(pre))));
});
return result;
}
const mainArr = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884'];
console.log("Random values: ", getRandomSet(mainArr, "shape", "size", "height"));
I modified the #ofek 's answer a bit. cuz for some reason the ??= is not working in react project.
function removeSimilars(input) {
let values = {};
for (let value of input)
if (!values[value.split("-")[0]]) {
values[value.split("-")[0]] = value;
}
return Object.values(values);
}
create a new array and loop over the first array and check the existing of element before in each iteration if not push it to the new array
I want to do something that seems simple but I cannot figure it out.
I want to use the javascript function 'filter' to find values in an array greater than a value and then return the indices that correspond the those filtered values (or values in that indice range from another array.
arr1 = [1,3,7,9,11];
arr1 = [2,4,8,10,12];
arr1.filter(x => x > 7);
// returns: [9,11]
// desired return: [4,5] (indices from arr1 where values from arr1 that were filtered) and/or [10,12]
// (values from arr2 where values from arr1 that were filtered)
I know the code is not right but I cannot figure out how to get desired result.
Any help would be appreciated. Thanks
You can use map in combination with filter to achieve this:
arr1.map((x, i) => [x,i]).filter(([x,i]) => x > 7).map(([x,i]) => i);
This maps the array to an array of pairs where the first element is the original number and the second is the original index. Then it filters the pairs by the first element of each pair before mapping it back to the indexes.
You can Array#reduce and do this in one run of the array by checking and transforming the data at once
const arr1 = [1,3,7,9,11];
const result = arr1.reduce((acc, x, index) => acc.concat(x > 7 ? index : []), []);
console.log(result);
You can do it like this:
var arr1 = [2,4,8,10,12];
console.log(arr1.filter(x => x>7).map(m => arr1.indexOf(m)))
returns [2, 3, 4]
The most efficient method would be to use reduce. Here I'm using array spread syntax to optionally add the index to the array used as the initial value of the accumulator.
var arr1 = [1,3,7,9,11];
var indexes = arr1.reduce((acc, cur, idx) => acc = cur > 7 ? [...acc, idx] : acc, []);
console.log(indexes);
Just add another map call and indexOf
PS: If there are duplicate values, indexOf return only first occurrence.
Alternatively, if you are not particular about filter, you can use reduce which can done with one iteration.
const arr1 = [1,3,7,9,11];
const arr2 = [2,4,8,10,12];
const filter = arr => arr.filter(x => x > 7).map(x => arr.indexOf(x));
console.log(filter(arr1))
console.log(filter(arr2))
const filter2 = arr => arr.reduce((acc, x, i) => (x > 7 && acc.push(i), acc), []);
console.log(filter2(arr1))
console.log(filter2(arr2))
I have an array that is filtered based on what the user types into a search box..
var x = ["Apple","Pear","Pineapple"];
var value = e.target.value;
var regex = new RegExp(`^${value}`, 'i');
var filtered = x.sort().filter(v => regex.test(v));
If I were to type "P" into the search box the console would print
["Pear","Pineapple"]
What I need however is another array of the original index position of Pear and Pineapple that would print the following
[1,2]
How would I go about achieving this?
You can do that in a single shot using reduce (read more about reduce here).
There is no need to filter, you can just generate another array, keep track of the index of the currently looped item (assuming you want the sorted index).
If you don't want the sorted index, just remove .sort. Not sure why it's there in the first place.
This solution requires a single iteration, which should be optimal (as long as you remove the unneeded sort).
var x = ["Apple","Pear","Pineapple"];
var value = 'P';
var regex = new RegExp(`^${value}`, 'i');
var filtered = x.sort().reduce((acc, next, i) => { // acc is the current accumulator (initially an empty array), next is looped item, i is item's index (what you want in the result).
return regex.test(next) && acc.push(i), acc // <-- if the regex test is successfull, `i` is pushed to the accumulator. In both cases (so, even if the regex fails) the accumulator is returned for the next iteration.
}, []); // <-- [] is the initial value of `acc`, which is a new empty array.
console.log(filtered);
Instead of filtering the array, filter the keys of the array instead:
var x = ["Apple","Pear","Pineapple"],
value ="P",
regex = new RegExp(`^${value}`, 'i'),
filtered = [...x.keys()].filter(i => regex.test(x[i]));
console.log(filtered)
keys() method returns a Array Iterator. So, you need to use spread syntax or Array.from() to convert it to an array
You could get first the value/index pairs, filter and get either the values or indices.
Intead of a RegExp, you could use String#startsWith, which has no problems of characters with special meanings.
var array = ["Apple", "Pear", "Pineapple"],
value = 'P',
filtered = array
.sort()
.map((v, i) => [v, i])
.filter(([v]) => v.startsWith(value)),
values = filtered.map(([v]) => v),
indices = filtered.map(([, i]) => i);
console.log(values);
console.log(indices);
You can get your indexes with indexOf() from the original array like so:
const x = ["Apple","Pear","Pineapple"];
var regex = new RegExp(`^P`, 'i');
const filtered = x.sort().filter(v => regex.test(v));
const filteredIndexes = filtered.map(v => x.indexOf(v));
console.log(filtered);
console.log(filteredIndexes);
You could also use reduce to do it all in one iteration like the so:
const x = ["Apple","Pear","Pineapple"];
var regex = new RegExp(`^P`, 'i');
const [filtered, filteredIndexes] = x.sort().reduce((acc, val, i) => {
// If the regex fits, add to the arrays
if(regex.test(val)) {
// Adding to the array via array spread operator
acc = [[...acc[0], val],[...acc[1], i]];
}
return acc;
}, [[],[]]); // Initial value of accumulator
console.log(filtered);
console.log(filteredIndexes);
I am trying to split an array of integers into an array of arrays by duplicate values. The original array is composed of a list of 6 digit integers, some of these integers come in pairs, others come in groups of 3 or 4s. I'd like to get these duplicates pushed to their own arrays and have all of these arrays of duplicates composed into an array of arrays that I can later loop through.
I've looked on in the lodash library for some method or combination of but can't quite find anything that seems to work. I've also tried a few different configurations with nested for loops but also am struggling with that.
const directory = "X/";
let files = fs.readdirSync(directory);
let first6Array = [ ];
for(i=0; i< files.length; i++){
let first6 = files[i].substring(0, 6);
first6Array.push(first6);
};
console.log(first6Array);
example output of first6Array:
[ '141848',
'141848',
'141848',
'142851',
'142851',
'143275',
'143275']
I'd like to end up with something like
let MasterArray = [[141848,141848,141848],[142851,142851],[143275,143275]];
You can use new Set() to filter out the duplicates.
Then you use the unique Array and filter for every value.
const firstArray = [ '141848', '141848', '141848', '142851', '142851', '143275', '143275'];
const numberArray = firstArray.map(Number);
const masterArray = [];
const unique = new Set (numberArray); // Set {141848, 142851, 143275}
unique.forEach(u => {
masterArray.push(numberArray.filter(e => e === u));
});
console.log(masterArray);
Using lodash, you can create a function with flow:
map the items by truncating them and converting to numbers.
groupBy the value (the default).
convert to an array of arrays using values.
const { flow, partialRight: pr, map, truncate, groupBy, values } = _;
const truncate6 = s => truncate(s, { length: 6, omission: '' });
const fn = flow(
pr(map, flow(truncate6, Number)),
groupBy,
values,
);
const firstArray = [ '141848abc', '141848efg', '141848hij', '142851klm', '142851opq', '143275rst', '143275uvw'];
const result = fn(firstArray);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Use reduce to create an object of arrays, indexed by number, and push to the associated array on each iteration (creating the array at the key first if needed), then get the values of the object:
const directory = "X/";
const files = fs.readdirSync(directory);
const output = Object.values(
files.reduce((a, file) => {
const num = Number(file.slice(0, 6));
if (!a[num]) a[num] = [];
a[num].push(num);
return a;
}, {})
);
It's pretty weird to have an array of identical values, though - you might consider a different data structure like
{
'141848': 3,
'142851': 2
}
to keep track of the number of occurrences of each number:
const output = files.reduce((a, file) => {
const num = file.slice(0, 6);
a[num] = (a[num] || 0) + 1;
return a;
}, {})
To obtain exactly the result you desire, you need a nested find, something like this should works:
const directory = "X/";
let files = fs.readdirSync(directory);
let first6Array = files.reduce((acc, value)=> {
let n = +value.substr(0, 6); // assumes it can't be NaN
let arr = acc.find(nested => nested.find(item => item === n));
if (arr) {
arr.push(n);
} else {
acc.push([n]);
}
return acc;
}, []);
console.log(first6Array);
Notice that an hashmap instead, with the value and the number of occurrence, would be better, also in term of performance, but I don't think it mind since you have really few elements.
Also, it assumes the first six characters are actually numbers, otherwise the conversion would fail and you'll get NaN.
It would be safer adding a check to skip this scenario:
let n = +value.substr(0, 6);
if (isNaN(n)) {
return acc;
}
// etc
I have 2 arrays of objects and I have to compare them, but the order of the objects DOES NOT matter. I can't sort them because I won't have their keys' names because the functions must be generic. The only information that I'll have about the array is that both array's objects have the same amount of keys and those keys have the same name. So the array1 must contain the same objects as the array2.
var array1 = [{"key1":"Banana", "key2":"Yammy"}, {"key1":"Broccoli", "key2":"Ew"}];
var array2 = [{"key1":"Broccoli", "key2":"Ew"}, {"key1":"Banana", "key2":"Yammy"}];
In the example, array1 must be equal array2.
I tryed to use the chai .eql() method but it didn't work.
The following solution:
will verify that the arrays have an equal number of elements
does not impose restrictions on keys (as to not contain a certain delimiter)
requires both keys and (string) values to be the same
has a time complexity of O(nlogn) (instead of O(n²) as some other solutions here)
function equalArrays(a, b) {
if (a.length !== b.length) return false;
const ser = o => JSON.stringify(Object.keys(o).sort().map( k => [k, o[k]] ));
a = new Set(a.map(ser));
return b.every( o => a.has(ser(o)) );
}
// Example
var array1 = [{"key1":"Banana", "key2":"Yammy"}, {"key1":"Broccoli", "key2":"Ew"}];
var array2 = [{"key1":"Broccoli", "key2":"Ew"}, {"key1":"Banana", "key2":"Yammy"}];
console.log(equalArrays(array1, array2)); // true
// Example with different key name
var array1 = [{"key0":"Banana", "key2":"Yammy"}, {"key1":"Broccoli", "key2":"Ew"}];
var array2 = [{"key1":"Broccoli", "key2":"Ew"}, {"key1":"Banana", "key2":"Yammy"}];
console.log(equalArrays(array1, array2)); // false
You can array#join each value of the object on an separator and then generate a new array of string and then compare each values using array#every and array#includes
var array1 = [{"key1":"Banana", "key2":"Yammy"}, {"key1":"Broccoli", "key2":"Ew"}];
array2 = [{"key1":"Broccoli", "key2":"Ew"}, {"key1":"Banana", "key2":"Yammy"}];
values = (o) => Object.keys(o).sort().map(k => o[k]).join('|'),
mapped1 = array1.map(o => values(o)),
mapped2 = array2.map(o => values(o));
var res = mapped1.every(v => mapped2.includes(v));
console.log(res);
You can do something like following:
For each object in each array you can calc its representation:
arr1.forEach( (obj) => {
obj.representation = '';
for (let key of Object.keys(obj)) {
obj.representation += obj[key];
}
}
Same for arr2
now you can sort both arrays by representation for example and then compare.
To sort do the following:
arr1.sort( (a,b) => { return a.representation > b.representation } );
arr2.sort( (a,b) => { return a.representation > b.representation } );
After sorting you can compare both arrays
let equal = arr1.every( (el, i) => arr2[i]===el );