I have an array of strings :
let arr = ["cap:1", "col:red", "cap:3", "cap:1", "col:blue", "screen:yes"]
and I want to have a new array, with one item from each category of substrings("cap", "col", "screen"),the one with smallest index:
let newArray = ["cap:1","col:red","screen:yes"]
//"cap:1" from newArray is arr[0]
I tried this way:
const newArr = (arr) => {
let c= []
let c = [...c, arr[0]]
for(let i = 1; i<arr.length; i ){
for (let j=0; j<c.length; j ){
if(arr[i].split(":")[0] !== c[j].split(":")){
c = [...c, arr[i]]
}
}
}
return c
}
but it goes into infinite loop and the result is something like this: ["cap:1","col:red","col:red","col:red","col:red","col:red","col:red","col:red"...
Could you please help me?
Thanks!
CodePudding user response:
This is a great use case for Array.Reduce. You can reduce the many values of your array into a compact object by splitting the entries into key-values and simply taking the first entry for the given key. Something like this should work for you:
const firstOfGroup = arr => arr.reduce((result, currentValue) => {
const parts = currentValue.split(':');
const key = parts[0];
const value = parts[1];
if (!result.hasOwnProperty(key)) {
result[key] = value;
}
return result;
});
If you specifically need the results placed in an array, you can reassemble the parts into that format, but iteration over the resulting object should be reasonably efficient.
CodePudding user response:
Here is an solution that might help you! First you need to map all the data so you get an key-value stream. This stream can then be reduced so only the first occurence will be saved.
let newArr = data.map(function(item){
return item.split(":")
}).reduce(function(acc, curr){
if(acc[curr[0]] === undefined){
acc[curr[0]] = curr[1]
}
return acc
})
CodePudding user response:
try with :
map
to get categoryfilter
to don't have duplicatearr.map(oneElement => oneElement.split(":")[0]) .filter((elem, index, a) => index === a.indexOf(elem));
let arr = ["cap:1", "col:red", "cap:3", "cap:1", "col:blue", "screen:yes"];
let categ = arr.map(oneElement => oneElement.split(":")[0]).filter((elem, index, a) => index === a.indexOf(elem));
console.log(categ);
CodePudding user response:
It goes on infinite loop since there are two nested for loop and one of the nested for loop is iterating an ever increasing array. Instead you can have an object which will be act as a reference.
let arr = ["cap:1", "col:red", "cap:3", "cap:1", "col:blue", "screen:yes"];
const newArr = (arr) => {
let c = [];
const suffixObj = {};
for (let i = 0; i < arr.length; i ) {
const getPrefix = arr[i].split(":")[0];
if (!suffixObj.hasOwnProperty(getPrefix)) {
c.push(arr[i]);
suffixObj[getPrefix] = true
}
}
return c
};
console.log(newArr(arr))
CodePudding user response:
You could take a Set
with an array of splitted first parts.
As result get an array from the set.
const
array = ["cap:1", "col:red", "cap:3", "cap:1", "col:blue", "screen:yes"],
types = [...new Set(array.map(s => s.split(':', 1)[0]))];
console.log(types);
CodePudding user response:
Your logic has no way of determining that the current element's prefix was not found in newArr
. Also, in the condition arr[i].split(":")[0] !== c[j].split(":")
you are comparing a string to an array, which always returns true
- string !== array.
May be you intended to write arr[i].split(":")[0] !== c[j].split(":")[0]
which would still not give you the desired result.
You can do away with the inner loop and check each element against newArr
using c.every(el => !...)
as follows:
let arr = ["cap:1", "col:red", "cap:3", "cap:1", "col:blue", "screen:yes"];
const newArr = (arr) => {
let c = [arr[0]];
for(let i = 1; i<arr.length; i ) {
if( c.every(el => !arr[i].startsWith( el.split(':')[0] )) ) {
c = [ ...c, arr[i] ];
}
}
return c;
}
console.log( newArr( arr ) );