How to I change the object in the array with For-of loop?
Following code:
let arr = ['a', 'b', 'c', 'd', 'e'];
for (let v of arr) {
if (v === 'c') {
v = 'f';
break;
}
}
console.log(arr);
I want to find the first letter c and change it to an f, but arr doesn't get changed, probably because it is not referenced ? But shouldn't the v of arr make that the object v is the same as the one in arr ?
Javascript does not create references to simple values such String. To get array referrenced, you need to let array be an array of objects like [{char : 'a'}, {char : 'b'}, ...]. Then in your iterator you can change elements of array through changing of the char property
let arr = [{char: 'a'}, {char :'b'}, ...];
for (let v of arr) {
if (v.char === 'c') {
v.char = 'f';
break;
}
}
v is not a reference to the array element, it's just a variable that is assigned the value that the array iterator yields. If you assign to it, only the variable v changes but not the array.
To do that, you need to explicitly reference the property with its index and assign to it:
let arr = ['a', 'b', 'c', 'd', 'e'];
for (let [i, v] of arr.entries()) {
if (v === 'c') {
arr[i] = 'f';
break;
}
}
console.log(arr); // ['a', 'b', 'f', 'd', 'e']
An iterator does not provide a way to mutate the underlying structure, you need to do it yourself.
As detailed in the MDN spec, let is declaring a new variable from a copy of your array element. So changing the v will not change the value in the array. This is shared by var and const and is simply just javascripts behaviour. When you create a new object, it starts empty.
Your loop is basically saying "For every element in arr, declare a variable holding a copy of it and then if that variable is c, change that copy to f"
Before you change v both, the array and v point to - or in this case have - the same value:
arr[2] -> 'c' <- v
After you change v it has a different value, but you didn't change the array:
arr[2] -> 'c' v -> 'f'
v and arr[2] are only placeholders, but different ones.
The correct answer:
let arr = ['a', 'b', 'c', 'd', 'e'];
let i = 0;
for (let v of arr) {
if (v == 'c') {
arr[i] = 'f';
break;
}
i++;
}
console.log(arr);
:-P
Related
I have an algorithm where some array will be given a new index, but the new index is not sequential. For the sake of time, just assume the new index is given to the array at random. Let's say I have this array:
const arr = [];
arr[5] = 'a'
arr[2] = 'b'
arr[9] = 'c'
arr[0] = 'd'
If I console.log this array to the output window, I get this:
['d', empty, 'b', empty × 2, 'a', empty × 3, 'c']
I'm wondering if it's possible to close/remove those empty gaps between values so the array entries are sorted by their actual index, so I can get this output:
['d', 'b', 'a', 'c']
Is there a short and easy way to do this?
You can just use Array.prototype.filter and filter out undefined values. You can take a shortcut by coercing them into boolean using the !! operator:
arr.filter(x => !!x);
This check is loose/dirty because anything falsy will be coerced to false, e.g. the numeric 0. If you really want to be strict and only filter out undefined, then you need a stricter predicate:
array.filter(x => typeof x !== 'undefined');
const arr = [];
arr[5] = 'a';
arr[2] = 'b';
arr[9] = 'c';
arr[0] = 'd';
console.log(arr);
console.log(arr.filter(x => !!x));
console.log(arr.filter(x => typeof x !== 'undefined'));
simply use Array.splice() method
to "clean up" your array, wthiut creating a new one.
need to use reverse index progression
const arr = [];
arr[5] = 'a';
arr[2] = 'b';
arr[9] = 'c';
arr[0] = 'd';
console.log(JSON.stringify(arr));
for (let i=arr.length; i-- > 0;)
{
if (arr[i]===undefined) arr.splice(i,1);
}
console.log(JSON.stringify(arr));
Assuming I have an array like this: [A, B, C, D, E, F]
, How can I group them like this:
[[A, B], [B, C], [C, D], [D, E], [E, F]]
(Notice how every last element is shared with the next group, but with the opposite index.)
I know this ain't a big deal of a problem, but I'm trying to keep it simple and short, maybe with Array.reduce() if possible:
arr.reduce(function (rows, key, index) {
return (index % 2 == 0 ? rows.push([key])
: rows[rows.length-1].push(key)) && rows;
}, []);
// Output: [[A, B], [C, D], [E, F]]
One liner solution is
arr.map((c, i) => [c, arr[i + 1]]).slice(0, -1)
SOLUTION 1
You can use map and filter here to achieve the result
At current index return an array which will contain current element and next element till last element
const arr = ['A', 'B', 'C', 'D', 'E', 'F'];
const result = arr
.map((c, i) => (i < arr.length - 1 ? [c, arr[i + 1]] : null))
.filter(Boolean);
console.log(result);
SOLUTION 2
You can also acheve this if you get all array combination and remove last one as:
const arr = ['A', 'B', 'C', 'D', 'E', 'F'];
const result = arr.map((c, i) => [c, arr[i + 1]]).slice(0, -1);
console.log(result);
Just with reduce method, you can add the current item and the item after it in an array, and then push this array into the accumulator of the reducer method, and before push you need to check if the current item isn't last item in the array.
const arr = ['A', 'B', 'C', 'D', 'E', 'F']
const result = arr.reduce((acc, item, index) => {
const nextItem = arr[index + 1]
nextItem ?? acc.push([item, nextItem])
return acc
}, [])
console.log(result)
If you don't want to stick to the reduce() approach here's another method using map() and slice().
const data = ['A', 'B', 'C', 'D', 'E', 'F'];
const result = data.map((_, i) => (i < data.length - 1 ? data.slice(i, i + 2) : null)).filter(Boolean);
console.log(result);
The simplest will be a standard for loop. It happens to also be shorter than many of the reduce() answers with no extraneous filters or conditions.
const arr = ['A', 'B', 'C', 'D', 'E', 'F'];
const result = [];
for (let i = 0; i < arr.length - 1; i++) {
result.push([arr[i], arr[i + 1]]);
}
console.log(result);
Alternatively a while loop is actually shorter if a little less transparent.
const arr = ['A', 'B', 'C', 'D', 'E', 'F'];
let result = [], i = 0;
while (i < arr.length - 1) {
result.push([arr[i], arr[++i]]);
}
console.log(result);
Let's say I have two arrays of same length:
const a = ['a', 'b', 'c', 'd'];
const b = [1, 1, 2, 1];
I want to join (.join('')) all consecutive items in a whose corresponding value in b (i.e. at the same index) are equal.
In this scenario, what I want to get is:
const result = ['ab', 'c', 'd']
Because a[0] and a[1] have the same corresponding value in b (i.e. b[0] === b[1]) and are consecutive in a, they are joined into the same string, forming a single item in result. However, although a[3]'s corresponding value in b is equal to a[0] and a[1]'s one, it's not joined to any of the latter as it isn't consecutive.
Just check if the value at b is the same at the given index and the sucessor.
const
a = ['a', 'b', 'c', 'd'];
b = [1, 1, 2, 1],
result = a.reduce((r, v, i) => {
if (b[i - 1] === b[i]) r[r.length - 1] += v;
else r.push(v);
return r;
}, []);
console.log(result);
You can use two seporate loops; one to combine the two arrays in an object and merge consecutive objects with the same id, and one to grab the other value from the first loop and create a new array.
const a = ['a', 'b', 'c', 'd'];
const b = [1, 1, 2, 1];
var step = [];
for (n = 0; n < a.length; n++) {
if(step[n-1] !== undefined && step[n-1].id === b[n]) {
step[step.length-1].text = step[step.length-1].text + a[n];
} else {
step.push({ id: b[n], text: a[n] });
}
}
var result = [];
for (i = 0; i < step.length; i++) {
result.push(step[i].text);
}
console.log(a);
console.log(b);
//console.log(step); //for testing
console.log(result);
The function unique_in_order which takes as argument a sequence and returns a list of items without any elements with the same value next to each other and preserving the original order of elements.
For example:
uniqueInOrder('AAAABBBCCDAABBB') == ['A', 'B', 'C', 'D', 'A', 'B']
uniqueInOrder('ABBCcAD') == ['A', 'B', 'C', 'c', 'A', 'D']
uniqueInOrder([1,2,2,3,3]) == [1,2,3]
What you want to do first is normalize your input such that whether it's a string or an array, it doesn't matter.
const input = Array.isArray(x) ? x : x.split('');
After the above, the input will always be an array. Now the logic for skipping is duplicates is quite simple
for (let i = 0; i < input.length; ++i) {
if (input[i] == input[i + 1]) continue
result.push(input[i])
}
You continue, i.e. skip each index in the input that is the same as the next for each index. Then for each element that isn't duplicated, you push into your result array.
The whole thing looks like this:
function uniqueInOrder(x) {
const result = [];
const input = Array.isArray(x) ? x : x.split('');
for (let i = 0; i < input.length; ++i) {
if (input[i] == input[i + 1]) continue
result.push(input[i])
}
return result
}
console.log(uniqueInOrder('AAAABBBCCDAABBB'));
console.log(uniqueInOrder('ABBCcAD'));
console.log(uniqueInOrder([1, 2, 2, 3, 3]));
If you're familiar with the filter function you can make it a one liner.
function uniqueInOrder(x) {
return (Array.isArray(x) ? x : x.split(''))
.filter((c, i) => c !== x[i + 1]);
}
console.log(uniqueInOrder('AAAABBBCCDAABBB'));
console.log(uniqueInOrder('ABBCcAD'));
console.log(uniqueInOrder([1, 2, 2, 3, 3]));
Offered is two different solutions, depending on what you want:
You can use Set() for unique sets. Simply adding the value to a set will retain the order and prevent unique values from being added.
For contiguously unique sets, you can use filter to iterate over an array.
If the argument is a string, this array is created by splitting on a blank string (.split(''))
When iterating over the array of input values, you can compare the current value to the previous; if they are different then return true
A true response will include the value in the array you will be creating as a result of the filter (which holds your unique values)
uniqueInOrder('AAAABBBCCDAABBB') == ['A', 'B', 'C', 'D', 'A', 'B']
uniqueInOrder('ABBCcAD') == ['A', 'B', 'C', 'c', 'A', 'D']
uniqueInOrder([1, 2, 2, 3, 3]) == [1, 2, 3]
function unique(input) {
var set = new Set(),
arr = input;
if (typeof input == 'string')
arr = arr.split('');
arr.forEach(val => {
set.add(val)
});
console.log('input:',input);
console.log('unique:',[...set]);
return [...set];
}
function uniqueInOrder(input) {
var arr = input;
if (typeof input == 'string')
arr = arr.split('');
var unique = arr.filter((val,i,arr)=>{
return val !== arr[i-1];
});
console.log('input:', JSON.stringify(input));
console.log('uniqueInOrder:', JSON.stringify(unique));
return unique;
}
I have an array like:
A = ['a', 'del', 'b', 'del', 'c']
how can i remove the elements del such that the result is,
B = ['a', 'b', 'c']
I tried the pop and indexOf method but was unable
Use filter() for filtering elements from an array
var A = ['a', 'del', 'b', 'del', 'c'];
var B = A.filter(function(v) {
return v != 'del';
});
console.log(B);
For older browser check polyfill option of filter method.
In case if you want to remove element from existing array then use splice() with a for loop
var A = ['a', 'del', 'b', 'del', 'c'];
for (var i = 0; i < A.length; i++) {
if (A[i] == 'del') {
A.splice(i, 1); // remove the eleemnt from array
i--; // decrement i since one one eleemnt removed from the array
}
}
console.log(A);