Can someone explain what is going on with `push` here? - javascript

It feels like push is behaving funny. Rather than just push to 1 index inside the forEach, it seems to be pushing to all 3 indexes. Am I missing something obvious?
let arrayToReduce = [ [ 1, 2, 3 ] ]
let reduced = arrayToReduce.reduce((arr, inner) => {
const copied = arr.slice()
inner.forEach((num, idx) => {
copied[idx].push(num)
})
return copied
}, Array(arrayToReduce[0].length).fill([]))
console.log(reduced)
Expected output: [[1], [2], [3]]
Actual output: [[1, 2, 3], [1, 2, 3], [1, 2, 3]]

push isn't the culprit, it is fill.
You've created an array the same length as the original and then filled it with a value.
That value is an array.
The same array.
So when you push a value to copied[0] you get a reference to that array and put a value into it.
And when you push a value to copied[1] you get a reference to that same array and put another value into it.

let arr = [ [ 7, 3, 47 ] ]
let reduced = arr.flat().map(e=>[e])
console.log(reduced)
//output: [[7], [3], [47]]
if you want your Expected output : [[1], [2], [3]]
Simply return index instead of item in inner array
let arr = [ [ 7, 3, 47 ] ]
let reduced = arr.flat().map((e,i)=>[i+1])
console.log(reduced)

Related

javascript equivalent to [x for x in array]

Is there any operation in Javascript just like [x for x in array] in python?
For example, I'm using javascript to reading a json file where there're dozens of (key, value) pairs needed to be handled(or transformed into other format). And I thought working in this way is stupid:
let transformed = []
for (let key in json){
transformed = [ /* doing some transform*/ ]
}
Is there anything like:
let transformed = [
lambda function1(key), lambda function2(value) for key, value in json
]
Thanks in advance.
The rough equivalent of Python's list comprehension is Array.map:
const myArray = [1, 2, 3]
const transformed = myArray.map((item) => item + 1)
// [2, 3, 4]
But your example is not about an array, but about an Object with keys and values. In Python, this would be a dict, and you'd use a dict comprehension along the lines of {function1(key): function2(value) for key, value in my_dict.items()}.
In JavaScript, you can turn such an object into an array with Object.entries, then perform the map, and finally transform it back into an object using Object.fromEntries:
const myObject = { a: 1, b: 2 }
const transformed = Object.fromEntries(Object.entries(myObject)
.map(([key, value]) => [key + 'x', value + 1]))
// { ax: 2, bx: 3 }
Note that fromEntries is fairly new and you might need to add a polyfill for it.
You can use a code likes this. You must use a function that handle operation on current single item.
const words = ['hello', 'bird', 'table', 'football', 'pipe', 'code'];
const capWords = words.forEach(capitalize);
function capitalize(word, index, arr) {
arr[index] = word[0].toUpperCase() + word.substring(1);
}
console.log(words);
// Expected output:
// ["Hello", "Bird", "Table", "Football", "Pipe", "Code"]
First of all, javascript does NOT support Associative Arrays. If you are used to them in Python, PHP, and other languages you need to do a little workaround in JS to achieve the same functionality.
The most common way to simulate an associative array is using an object.
let testObject = {name: "Color", value: "Red"};
And then you push every object into an array so you end up with something like this:
let testArray = [{name: "Color", value: "Red"}, {name: "Color", value: "Blue"}];
Once you have this array consisting of objects, you can use map function to go through every object in the array and do whatever you want with it.
testArray.map((item, index) => {
console.log("The value of "+index+". item is: "item.value);
})
You can use Array.map() function. It work pretty like Array.forEach() function
const numbers = [1, 2, 3, 4, 5]
let newArray = numbers.map((element) => {
return element * 2
})
console.log(newArray) // excepted : [ 2, 4, 6, 8, 10 ]
It can be reduce using
const numbers = [1, 2, 3, 4, 5]
let newArray = numbers.map(element => element * 2)
console.log(newArray) // excepted : [ 2, 4, 6, 8, 10 ]
For more informations, you can this documentation https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/map

Basic Javascript, How can i filter an array by numeric value?

this is my first question on this community and i'm a novice programmer with JavaScript.
I have something like this:
let dog = [["extra small", 2], ["small", 5], ["medium", 7], ["big", 9], ["extra big", 12]];
Taking the data of the previous array, i want to create a new array just with the numeric values, for example:
ages = [2, 5, 7, 9, 12]
I tried to use "filter", but i don't know how to properly use it, also i tried to search some references to make it work but i couldn't.
Thanks in advance (and sorry for my poor english, but i suppose you get the idea).
You can first use Array#map to get just the numbers and then Array#sort to sort the numbers
let dog = [
["extra small", 2],
["small", 5],
["medium", 7],
["big", 9],
["extra big", 12]
];
let ages = dog.map(([size, age]) => age).sort((a, b) => a - b);
console.log(ages);
Here are my thoughts on how to achieve this.
Using Array#Map and Array#filter.
Basically, mapping each element of the array, then checking for the numeric values in the subArray using JavaScript#isNaN() and
returning the numbers.
isNaN() checks if the value type is not a number. !isNaN() reverses that response.
flat() is used to flatten the final result to a single array. Alternatively, you can change map() to flatMap()
// map(), isNaN(), filter(), flat()
let newArr = dog.map((arr) => arr.filter((val) => !isNaN(val))).flat();
console.log(newArr); // [ 2, 5, 7, 9, 12 ]
// flatMap(), isNaN(), filter()
let newArr = dog.flatMap((arr) => arr.filter((val) => !isNaN(val)));
console.log(newArr); // [ 2, 5, 7, 9, 12 ]
Using function.
This is similar to the first, however, instead of using map() we use a Array#forEach to loop through the array.
function getNumeric(array) {
let result = [];
array.forEach((arr) => {
let res = arr.filter((a) => !isNaN(a));
result.push(...(res));
});
return result;
}
let newArr = getNumeric(dog);
console.log(newArr); // [ 2, 5, 7, 9, 12 ]
let dog = [
["extra small", 2],
["small", 5],
["medium", 7],
["big", 9],
["extra big", 12]
];
const newArr = dog.map(item => {
return item[1]
})
console.log(newArr);

How to build a Set of unique Arrays?

I want to add many arrays to a Javascript set, and ensure that only unique arrays are added to the set. However, when I try adding the same array multiple times, it is always added instead of rejected. The .has() method always returns false as well. How do I fix this?
const mySet = new Set();
mySet.add([1, 2, 3]);
mySet.add([4, 5]);
mySet.add([1, 2, 3]);
console.log(mySet);
// Gives: Set(3) { [ 1, 2, 3 ], [ 4, 5 ], [ 1, 2, 3 ] }
// I want: Set(2) { [ 1, 2, 3 ], [ 4, 5 ] }
console.log(mySet.has([1, 2, 3]));
// Gives: false
// I want: true
I'd use a Map instead, indexed by the stringified version of the array:
const map = new Map();
const addToMap = arr => map.set(JSON.stringify(arr), arr);
addToMap([1, 2, 3]);
addToMap([4, 5]);
addToMap([1, 2, 3]);
console.log([...map.values()]);

Why array loops works in Python to remove duplicated entries, but JS don't?

I'm new in programming and I already have a little bit of background in Python.
At the moment, I'm studying Javascript and I was doing an exercise that should remove duplicate entries in an array.
I don't understand why the logic bellow doesn't work in JS, but works in Python. Can someone explain to me?
Javascript:
let array = [3, 3, 3, 4, 5];
let noRepetition = [];
for (let i of array) {
if (!(i in noRepetition)) {
noRepetition.push(i)
}
}
console.log('Before ', array);
console.log('After ', noRepetition);
Output:
Before [ 3, 3, 3, 4, 5 ]
After [ 3, 3, 3, 4, 5 ]
Python:
array = [3, 3, 3, 4, 5]
noRepetition = []
for i in array:
if not i in noRepetition:
noRepetition.append(i)
print(f'Before {array}')
print(f'After {noRepetition}')
Output:
Before [3, 3, 3, 4, 5]
After [3, 4, 5]
Actually, the in operator in javascript is not working as in python and checks keys (for an array, indexes).
> "a" in ["a", "b"]
false
> 1 in ["a", "b"]
true
> 2 in ["a", "b"]
false
You can use includes:
> ["a", "b"].includes("a")
true
And this should work as you expect.
You should also check libraries like lodash which provide a function for this.
Also you might want to consider using Sets if you want your data structure to be duplicate-free:
Array.from(new Set([2, 1, 3, 1]))
[ 2, 1, 3 ]
JavaScript: in operator parameters description:
A string or symbol representing a property name or array index (non-symbols will be coerced to strings).
which mean:
// Arrays
let trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']
0 in trees // returns true
3 in trees // returns true
6 in trees // returns false
'bay' in trees // returns false (you must specify the index number, not the value at that index)
'length' in trees // returns true (length is an Array property)
Symbol.iterator in trees // returns true (arrays are iterable, works only in ES2015+)
// Predefined objects
'PI' in Math // returns true
// Custom objects
let mycar = {make: 'Honda', model: 'Accord', year: 1998}
'make' in mycar // returns true
'model' in mycar // returns true
in operator - JavaScript | MDN

Filter array of objects against another array of objects. Remove items with array values that matches those inside another array of objects

I've used .filter successfully in the past, but I can't figure out this use case.
I want to return a clone of the array chordLibrary (presumably using .filter). But I want to remove any items/objects from this new array where any array value of the property name notesInChord happens to match any of the array values of badNotes.keyIndex.
To clarify, I will compare each item in chordLibrary against every item in badNotes and remove an item from chordLibrary if its array values matches any of the array values in any of the items items in badNotes.
In the following example, you can see that the first item in chordLibrary includes the array value 5, and so that item is removed in the result.
const chordLibrary = [
{ notesInChord: [5, 8], chordName: 'Major' },
{ notesInChord: [4, 8], chordName: 'Minor' },
{ notesInChord: [8], chordName: '5' }
];
const badNotes = [
{"keyIndex":[1],"keyName":"C#"},
{"keyIndex":[3],"keyName":"D#"},
{"keyIndex":[5],"keyName":"E"}
];
// example result: "
const newChordLibrary = [
{ notesInChord: [4, 8], chordName: 'Minor' },
{ notesInChord: [8], chordName: '5' }
];
I assume I need to nest or use a for loop or forEach to do this, but I can't figure it out.
ES6 solutions are ok.
Thanks!
In the filter you can use a custom method that searches in the notesInChord if any of them are found in badNotes using find as follows:
const chordLibrary = [
{ notesInChord: [5, 8], chordName: 'Major' },
{ notesInChord: [4, 8], chordName: 'Minor' },
{ notesInChord: [8], chordName: '5' }
];
const badNotes = [
{"keyIndex":[1],"keyName":"C#"},
{"keyIndex":[3],"keyName":"D#"},
{"keyIndex":[5],"keyName":"E"}
];
function getGoodNotes(chordList){
return chordList.filter((chord)=>{
if(!containsBadNote(chord.notesInChord))
return chord;
});
}
function containsBadNote(notesInChord){
for(let i = 0; i < notesInChord.length; i++){
var note = notesInChord[i];
if(badNotes.find((n)=> n.keyIndex[0]==note)!=null)
return true;
}
return false;
}
console.log( getGoodNotes(chordLibrary) );

Categories