I want to remove all 'main-1-3' elements inside arrays:
const a = {
white: ['main-1-1'],
red: ['main-1-3'],
orange: [],
green: [],
blue: [],
}
const colors = ['white', 'red', 'orange', 'green', 'blue'];
for(let i = 0; i < colors.length; i++) {
a[colors[i]].splice(a[colors[i]].indexOf('main-1-3'), 1);
}
console.log(a)
But as you see if there is no such element other elements are removed too! I want to only remove the 'main-1-3' in all of the arrays?
How can I fix this?
You should first check that the item really is in the array. indexOf an item that isn't in the array will return -1, which will mess up the splice call:
const a = {
white: ['main-1-1'],
red: ['main-1-3'],
orange: [],
green: [],
blue: [],
}
const colors = ['white', 'red', 'orange', 'green', 'blue'];
for(let i = 0; i < colors.length; i++) {
const index = a[colors[i]].indexOf('main-1-3');
if (index >= 0) {
a[colors[i]].splice(index, 1);
}
}
console.log(a)
You could just loop over a's Object.entries and filter out all the main-1-3 elements.
const a = {
white: ['main-1-1'],
red: ['main-1-3', 'main-1-1'],
orange: [],
green: [],
blue: ['main-1-2'],
}
for (let [key, arr] of Object.entries(a)) {
a[key] = arr.filter(el => el !== 'main-1-3');
}
console.log(a);
iterate through each array and filter out the item main-1-3:
const a = {
white: ['main-1-1'],
red: ['main-1-3'],
orange: [],
green: [],
blue: [],
}
const colors = ['white', 'red', 'orange', 'green', 'blue'];
colors.forEach(e => a[e] = a[e].filter(n => n !== 'main-1-3'))
console.log(a)
Just check whether string 'main-1-3' exist in arrays in a.
Because if the string main-1-3 doesnot exist in the arrays in object a, the index will return -1.
Array.splice(-1, 1) will delete the last node in the array, this is what happening in your case.
Array.splice(-1, 1) Example
const myArray = [1, 2, 3, 4];
myArray.splice(-1, 1);
console.log(myArray); // Last element removed
As you see in the above example, Array.splice(-1, 1) deletes the last node. So you have to ensure that your index a[colors[i]].indexOf('main-1-3') is not -1 or else the last nodes in your array will be deleted.
Working Fiddle
const a = {
white: ['main-1-1'],
red: ['main-1-3'],
orange: [],
green: [],
blue: [],
}
const colors = ['white', 'red', 'orange', 'green', 'blue'];
for (let i = 0; i < colors.length; i++) {
const index = a[colors[i]].indexOf('main-1-3');
if (index > -1) {
a[colors[i]].splice(index, 1);
}
}
console.log(a)
Related
Tallying which color has a greater value in each array element for data. Then push the higher valued color into an empty object, and/or increment that color by 1. Lastly sort the totals object highest to lowest in terms of the totals property values and return highest valued color
Struggling with how to map over this structure array since property keys are not uniform. Should I destructure it?
*I can redesign data structure as needed, and if it's easier to solve with a different design, please let me know!
data = [
{ orange: 4, green: 4},
{ green: 0, yellow: 0},
{ yellow: 1, orange: 4 },
{ blue: 2, green: 1 },
{ blue: 2, yellow: 1 },
{ green: 3, yellow: 2 },
{ green: 1, blue: 3},
{ green: 5, yellow: 2 },
]
```
```
totals = {
blue: 3,
green: 2,
orange: 1,
}
```
solution:
```
highValueColor = blue
```
// PSEUDOCODE
//map over the array => data.map()
//identify highest value between two elements => propA - propB
//check to see if the color's (key) in the element has already been added to totals object
//IF the key does not yet exist, create a property in the tally object with the color(key) and set its value to 1
//IF the key is already listed in tally object, increment its property value by 1 => ++
//sort totals object => Math.max()
//return highest value color
`
Not sure how much help this is, #hopzebordah answer seems fine except that it looks like it counts a colour when both colours have the same value. (e.g. { orange: 4, green: 4} gets counted as orange).
I added a version with map in the comments as you seemed to be interested in that, but I might have misunderstood what you were trying to achieve.
If you don't need the sorted object and only the highest value, then you probably don't need to sort the object first. Hopefully highest_value_unsort demonstrates this.
const data = [
{ orange: 4, green: 4},
{ green: 0, yellow: 0},
{ yellow: 1, orange: 4 },
{ blue: 2, green: 1 },
{ blue: 2, yellow: 1 },
{ green: 3, yellow: 2 },
{ green: 1, blue: 3},
{ green: 5, yellow: 2 },
];
const pick_color = (color_obj) => {
const [[color1, val1], [color2, val2]] = Object.entries(color_obj);
return val1 === val2 ?
null :
val1 > val2 ?
color1 :
color2;
};
const unsorted = {};
for(const color_obj of data) {
const color = pick_color(color_obj);
if(color) {
unsorted[color] = (unsorted[color] ?? 0) + 1;
}
}
// version of the above using reduce:
// const unsorted = data.reduce((acc, val) => {
// const color = pick_color(val);
//
// return !color ?
// acc :
// { ...acc, [color]: (acc[color] ?? 0) + 1 };
// }, {});
// version of the above using map then reduce:
// const unsorted = data
// .map(pick_color)
// .reduce(
// (acc, color) => !color ?
// acc :
// { ...acc, [color]: (acc[color] ?? 0) + 1 },
// {}
// );
const sorted = Object.fromEntries(
Object.entries(unsorted)
.sort(([, a_val], [, b_val]) => b_val - a_val)
);
const highest_value = Object.entries(sorted)[0][0];
const highest_value_unsort = Object.entries(unsorted)
.reduce(
(acc, entry) => entry[1] > acc[1] ? entry : acc,
['none', 0]
)[0];
console.log(sorted);
console.log(highest_value);
console.log(highest_value_unsort);
Some reference links in case you're not familiar with some of the features used above:
reduce
Nullish coalescing operator (??)
Spread syntax
You're in luck as you are using JS!
It's super easy (or loosey-goosey, depending on your personal preference) to set/get data inside of JS objects using their keys using the { [someVariable]: value } notation. You can also check for existence of a key inside of an object using the in operator, like so:
const obj = { red: 'foo' };
const red = 'red';
console.log(red in obj) // true
console.log('red' in obj) // true
console.log(blue in obj) // false
So, combining that with a couple simple loops we can get this:
const data = [
{ orange: 4, green: 4},
{ green: 0, yellow: 0},
{ yellow: 1, orange: 4 },
{ blue: 2, green: 1 },
{ blue: 2, yellow: 1 },
{ green: 3, yellow: 2 },
{ green: 1, blue: 3},
{ green: 5, yellow: 2 },
];
const totals = {};
for (const colors of data) {
const [color1, color2] = Object.keys(colors);
let color = color1;
if (colors[color1] < colors[color2]) {
color = color2
}
totals[color] = totals[color] ? totals[color] + 1 : 1;
}
console.log(totals) // { orange: 2, green: 3, blue: 3 }
This isn't a performant solution by any means, but it is mainly held back by the structure of your data and needing to iterate over every value in order to check each key and its corresponding value.
Objects are very powerful in JS and form the basis of its flexibility. You may be able to leverage this to get a faster solution if you are eventually held back by performance issues depending on the size of the dataset.
I have this array:
const vals = ['blue', 'blue', 'green', 'blue', 'yellow', 'yellow', 'green']
I would like to reduce it to this:
['blueblue', 'green', 'blue', 'yellowyellow', 'green']
Where it concats the values if they are the same. Once the value changes it starts again.
Trying to use reduce but not sure how to make it work as the acc needs to be a string and an array depending on if the value is the same or not!
let lastType = vals[0]
const groups = vals.reduce((acc, value) => {
if (lastType === value) {
acc += value // string
}
lastType = value
return acc.push(value)
}, [])
The final result is an array, so that is what acc should be.
Instead of appending value to acc, append it to the last element of the array:
const vals = ['blue', 'blue', 'green', 'blue', 'yellow', 'yellow', 'green']
let lastType = null;
const groups = vals.reduce((acc, value) => {
if (lastType === value) {
acc[acc.length - 1] += value;
} else {
lastType = value
acc.push(value)
}
return acc;
}, [])
console.log(groups);
The use of lastType in a closure is a bit of a code smell, as is the use of mutability in the reducer.
A preferable, though slightly more verbose approach:
const vals = ['blue', 'blue', 'green', 'blue', 'yellow', 'yellow', 'green']
const { groups } = vals.reduce(({ lastType, groups }, value) => {
if (lastType === value) {
return {
lastType,
groups: [
...groups.slice(0, groups.length - 2),
groups[groups.length - 1] + value
],
};
}
return {
lastType: value,
groups: [...groups, value],
};
}, { groups: [], lastType: null })
console.log(groups);
You need to check the element at the index in front of the actual index and add a new string to the accumulator.
const
values = ['blue', 'blue', 'green', 'blue', 'yellow', 'yellow', 'green'],
result = values.reduce((accumulator, value, index, array) => {
if (value === array[index - 1]) accumulator[accumulator.length - 1] += value;
else accumulator.push(value);
return accumulator;
}, []);
console.log(result);
Push an empty string to the accumulator if the type is new. Remember that .push returns the new length of the array, so don't return it at the bottom of the function - instead, return the whole accumulator:
const vals = ['blue', 'blue', 'green', 'blue', 'yellow', 'yellow', 'green']
let lastType;
const groups = vals.reduce((acc, value) => {
if (lastType !== value) {
acc.push('');
lastType = value;
}
acc[acc.length - 1] += value;
return acc;
}, [])
console.log(groups);
You need to keep track of a bit more. Basic way of doing it is using an bject to hold the state.
const vals = ['blue', 'blue', 'green', 'blue', 'yellow', 'yellow', 'green']
const groups = vals.reduce((acc, value, index, array) => {
// is it the same, duplicate it
if (acc.lastType === value) {
acc.current += value;
} else {
// did we have a previous value? Add it to the array
if (acc.lastType) {
acc.result.push(acc.current);
}
// set the current type
acc.current = value;
acc.lastType = value;
}
// if we are at the end, add what we have to the array
if (index+1===array.length) {
acc.result.push(acc.current);
}
return acc;
}, { result: [], current: '', lastType: null }).result;
console.log(groups);
I have this array with objects that look like this
{
n: 15,
color: "red"
}
I am trying to sort it with the below function
async insertionSort() {
let len = this.array.length;
let value;
let i;
let j;
//let current;
// let arr = this.array;
for (i = 0; i < len; i++) {
value = this.array[i].n;
//current = this.array[i];
for (j = i - 1; j > -1 && this.array[j].n > value; j++) {
//arr[j + 1] = arr[j];
// HF.arraySwap(this.array, this.array[j + 1], this.array[j]);
this.array[j + 1] = this.array[j];
}
// arr[j + 1] = value;
HF.arraySwap(this.array, this.array[j + 1], this.array[i]);
await HF.sleep();
}
}
** I cant use array.sort(...) because i am trying to make a visualization of the algorithm, i am using objects in order to change the color of the bars i am rendering on the screen **
When i hit the second for loop i get an error of "Cannot read property 'n' of undefined", when i run it with just numbers it works fine but when i try it with objects it gives the error.I know now i am running out of the array, is there a way i can overcome this and still sort the array of objects? Also, i am using VueJS to display all of this
Try against this.array[i].n write this.array[i][n]
And against this.array[j].n write this.array[j][n]
On the first iteration i=0, you start second loop with value j=i-1 which is -1. Array doesn't contain item with index -1: array[-1] is undefined. As soon as JavaScript can compare variables of different types it works with numbers because comparison of number and undefined won't trigger an error
By the way you can use Array.proototype.sort method, it will look like:
console.log(myArr.sort((a,b) => a.n - b.n))
<script>
const myArr = [
{ n: 1, color: "red" },
{ n: 44, color: "orange" },
{ n: 13, color: "yellow" },
{ n: 8, color: "green" },
{ n: 2, color: "blue" }
];
</script>
Is there any reason why not use sort method like this?:
const arr = [
{ n: 10, color: "red" },
{ n: 20, color: "yellow" },
{ n: 15, color: "black" },
{ n: 7, color: "white" },
{ n: 23, color: "blue" }
];
const ascSorted = arr.sort((a, b) => a.n - b.n);
const descSorted = arr.sort((a, b) => b.n - a.n);
console.log(ascSorted);
// [
// { n: 7, color: "white" },
// { n: 10, color: "red" },
// { n: 15, color: "black" },
// { n: 20, color: "yellow" },
// { n: 23, color: "blue" }
// ];
How can I streamline this code ?
I think it might have better way to refactor .
const aa = ['red', 'yellow', 'blue']
const bb = { first: 0, second: 1, third: 2 }
const cc = { ...bb }
cc.first = aa[cc.first]
cc.second = aa[cc.second]
cc.third = aa[cc.third]
You can use .reduce() and Object.entries() methods:
const aa = ['red', 'yellow', 'blue']
const bb = { first: 0, second: 1, third: 2 }
const cc = Object.entries(bb)
.reduce((r, [k, i]) => (r[k] = aa[i], r), {});
console.log(cc);
This is a solution that still works after adding or removing an item from aa or bb, without need to change your code.
const aa = ['red', 'yellow', 'blue']
const bb = { first: 0, second: 1, third: 2 }
const cc = {};
for(var key in bb)
cc[key] = aa[bb[key]];
> var lst = ['red', 'blue', 'yellow'];
> someFunc(lst);
[('red', 0), ('blue', 1), ('yellow', 2)]
Is there any way to do this in Javascript/JQuery? I know that I can simply just make a for loop and convert each of the original list's element to what I want, but I was wondering if there was a built in way of doing this.
Thanks!
You could use Array#map and return for each item an array with the value and the index.
var lst = ['red', 'blue', 'yellow'],
array = lst.map(function (a, i) { return [a, i]; });
console.log(array);
You can leverage the map() function that is providing you both the value and and index of each item in the array:
lst.map(function(v, i) { return { value: v, index: i }; } );
See MDN
With map method in ES6 :
var lst = ['red', 'blue', 'yellow'];
var array = lst.map((item, index) => [item, index])
console.log(array); // [ [ 'red', 0 ], [ 'blue', 1 ], [ 'yellow', 2 ] ]