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 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 a multidimentional array:
(3) [Array(1), Array(1), Array(1)]
0:["('idDocDetail','0','$createdBy')"]
1:["('idDocDetail','2','$createdBy'),('idDocDetail','4','$createdBy')"]
2:["('idDocDetail','0','$createdBy')"]
I need to replace the string value idDocDetail with the index number, like this.
(3) [Array(1), Array(1), Array(1)]
0:["('0','0','$createdBy')"]
1:["('1','2','$createdBy'),('1','4','$createdBy')"]
2:["('2','0','$createdBy')"]
I'm trying to use replace, but I got the replace is not a function error.
array.forEach(function(item, index) {
return item.toString().replace('idDocDetail', index);
});
what am I doing wrong? Replace is the right way to do this?
I do recommend you to learn to perform changes in immutable manner. This is where Array.prototype.map plays well
const data = [
["('idDocDetail','0','$createdBy')"],
["('idDocDetail','2','$createdBy'),('idDocDetail','4','$createdBy')"],
["('idDocDetail','0','$createdBy')"]
]
const modified = data.map((item, index) =>
item.map(str => str.replace(/idDocDetail/g, index ))
)
modified.forEach(x => console.log(JSON.stringify(x)))
Here, this works for your code structure. It uses map() to produce a new array by just replacing the string of interest with the index.
EDIT: Added a nested map for clarity + regular expression to find all instances of 'idDocDetail' in the string, not just the first one. replace method when given a raw string value only handles the first instance of a string occurring.
const array = [["('idDocDetail','0','$createdBy')"],
["('idDocDetail','2','$createdBy'),('idDocDetail','4','$createdBy')"],
["('idDocDetail','0','$createdBy')"]]
var find = 'idDocDetail';
var re = new RegExp(find, 'g');
let newArray = array.map((val, i) => val.map(string => {
return string.replace(re, i)
}))
console.log(newArray)
You can loop over your array and edit it.
let array = [
["('idDocDetail','0','$createdBy')"],
["('idDocDetail','2','$createdBy'),('idDocDetail','4','$createdBy')"],
["('idDocDetail','0','$createdBy')"],
];
array.forEach((e, i) => {
array[i] = [e[0].replace(/idDocDetail/g, i)];
});
console.log(array);
You can not replace an item by calling a method on the item being replaced. Instead you need to call it on the array. You can do it this way:
for (var i=0; i<array.length; i++) {
array[i][0] = i;
}
forEach ignores the return of the callback. You need to assign to the original array at the current index.
var array = [
["('idDocDetail','0','$createdBy')"],
["('idDocDetail','2','$createdBy'),('idDocDetail','4','$createdBy')"],
["('idDocDetail','0','$createdBy')"]
];
array.forEach(function(item, index) {
array[index] = item.map(s => s.replace('idDocDetail', index));
});
console.log(array);
Got a string that is a series of 0 or 1 bit and an array of values, if in the string are characters that are set to 1, I need to return the corresponding value from the array.
example: mystring = "0101"; myarray =["A","B","C","D"]; then result = "B,D"
how can I get this result?
for(var i=0;i<mystring.length;i++){
if(mystring[i] != 0)
{
result = myarray[i];
}
}
Your code seems to work just fine, so you can just add another array and push the values on to that:
var result = [];
for (var i = 0 ...
result.push(myarray[i]);
http://jsfiddle.net/ExplosionPIlls/syA2c/
A more clever way to do this would be to apply a filter to myarray that checks the corresponding mystring index.
myarray.filter(function (_, idx) {
return +mystring[idx];
})
http://jsfiddle.net/ExplosionPIlls/syA2c/1/
Iterate through the characters in the binary string, if you encounter a 1, add the value at the corresponding index in the array to a temporary array. Join the temporary array by commas to get the output string.
I am not really sure if this is what you are looking for, but this returns the array of matches.
var result = [];
for(var i=0;i<mystring.length;i++){
if(parseInt(mystring[i]) !== 0 ) {
result.push(myarray[i]);
}
}
return result;
result = new Array();
for(var i=0;i