I've got a matrix where rows don't necessarily have the same length:
The following are musical tokens in the format of solfege.
const notes = [
[ 'do5', 'mi5' ],
[ 'mi6', 'so6', 'ti6', 're7' ],
[ 'so7', 'ti7', 're8', 'fa8' ],
[ 'la3', 'do4', 'mi4' ],
[ 'fa2', 'la2' ],
[ 're2' ],
[ 'ti1', 're2', 'fa2' ]
];
I have a function that converts these tokens into equivalent alphabetic tokens (for example: fa2 would be converted to F2 using my function).
I would like to be able to iterate over this matrix, and return the transformed matrix, which should retain the same dimensions.
Thanks,
Nakul
Here's what you probably want:
const notes = [
[ 'do5', 'mi5' ],
[ 'mi6', 'so6', 'ti6', 're7' ],
[ 'so7', 'ti7', 're8', 'fa8' ],
[ 'la3', 'do4', 'mi4' ],
[ 'fa2', 'la2' ],
[ 're2' ],
[ 'ti1', 're2', 'fa2' ]
];
// replace this function with your own converter
function convert(note) {
return note.toUpperCase();
}
for (let i = 0; i < notes.length; i++) { // for each row
// map will iterate through the row, converting each note
notes[i] = notes[i].map(convert);
}
The part map(convert) is just a shorter form of map(note => convert(note)).
This is not very efficient, as map() will create a new array for each row, but in your case it's probably more important that the code is readable rather than performant, so that's fine.
You can use the new Array.prototype.flat() function, but, if you want wider support (.flat() is ignored by both Edge and IE), then I would use two for..of loops.
const arr = [
[ 'do5', 'mi5' ],
[ 'mi6', 'so6', 'ti6', 're7' ],
[ 'so7', 'ti7', 're8', 'fa8' ],
[ 'la3', 'do4', 'mi4' ],
[ 'fa2', 'la2' ],
[ 're2' ],
[ 'ti1', 're2', 'fa2' ]
];
// Modern JavaScript
for (const item of arr.flat()) {
console.log(item);
}
console.log('----');
// More widely supported JavaScript
for (const subarray of arr) {
for (const subitem of subarray) {
console.log(subitem);
}
}
Related
I have below scenarios to handle.
let data = [
[ "ALISHA", "SUICA", "PASMO" ],
[ "HARMONY" ],
[ "OCTOPUS" ]
]
let data1 = [
[ "ALISHA", ],
[ "HARMONY" ],
[ "OCTOPUS", "SUICA", "PASMO" ]
]
For both of the above data, i want the result to look like this.
let result = [
[ "ALISHA" ],
[ "HARMONY" ],
[ "OCTOPUS" ],
[ "SUICA" ],
[ "PASMO" ]
]
Can someone please let me know how to achieve this. I tried the following but no success
let result = []
for (let i = 0; i < data.length; i++) {
let split = data[i].split(","); // just split once
result.push(split[0]); // before the comma
}
we will use forEach method on main array inside forEach we will use if condition if is array and length more than 1 will add another forEach method and push sub array to main array after that remove sub array
look like that
let data = [
["ALISHA"],
["HARMONY"],
["OCTOPUS", "SUICA", "PASMO"]
]
data.forEach((cur, index) => {
if (Array.isArray(cur) && cur.length > 1) {
cur.forEach(cur => data.push([cur]))
data.splice(index, 1);
}
})
console.log(data)
Uses Array.reduce extract all elements, then convert to [string] by Array.map.
const data = [
[ "ALISHA" ],
[ "HARMONY" ],
[ "OCTOPUS", "SUICA", "PASMO" ]
]
console.log(
data.reduce((pre, cur) => [...pre, ...cur], []).map(item => [item])
// data.reduce((pre, cur) => pre.concat(...cur), []).map(item => [item]) // different methods but same logic (uses Array.concat instead of spread operator)
)
You can use flat and map
const data = [["ALISHA"], ["HARMONY"], ["OCTOPUS", "SUICA", "PASMO"]];
const result = data.flat().map((a) => [a]);
console.log(result);
I am trying to add a copy of an array to another array with array.slice(), but when I update the original, it updates the copy that I added. How can I add a copy that isn't altered when the original is altered?
I've tried using result.unshift[...curRow], and result.unshift(curRow.slice()) when I add
function game(n) {
var result = [];
let row1=[[1, 2]];
for (var i=1;i<n;i++){
var cur = row1[i];
var prev = row1[i - 1];
row1.push([prev[0] + 1, prev[1] + 1]);
}
result.push(row1.slice());
let curRow = row1.slice();
for (var i=1;i<n;i++){
for (var j = 0; j<curRow.length ;j++){
curRow[j][1]++;
}
result.unshift(curRow.slice());
console.log('curRow =',curRow);
console.log('result = ', result)
}
console.log('result = ', result)
return result
}
game(3);
This is my current output:
'result ='[ [ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ] ] ]
'result = '[ [ [ 1, 3 ], [ 2, 4 ], [ 3, 5 ] ], [ [ 1, 3 ], [ 2, 4 ], [ 3, 5 ] ] ]
'result = '[ [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ], [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ], [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ] ]
I want the result array to contain each iteration of the curRow array, instead of just having copies of the latest one.
In JavaScript, objects/arrays, also known as non-primitive types, are given a reference, rather than value. Therefore, this particular reference points to the object's location in the memory. That variable you are working with has a 'reference' rather than containing an actual 'value'. This is why it is mutated when you use it on the game() function.
To work with that, you should create a shallow copy of that array, before making any manipulation/mutation to it.
const copy = originalArray.map(element => ({...element}));
Now, all changes to the copy array will not be applied to originalArray.
Because in Javascript Arrays are handled by reference, when you reasign an array to a new variable, the new variable only holds a reference to the original array. Any alteration on the original array will be reflected in any of its instances/references (beucause they are essentially the same object).
Since the ES6 version of the standard we have Array.from() to perform copies or duplicates of the contents of an Array.
It's my favorite way to go, is fast, safe and readable.
The Array.from() method creates a new, shallow-copied Array instance from an array-like or iterable object. Extended documentation here
Check the example :
let a = [1,2,3,4,5];
let b = Array.from(a);
// modify first array to test
a[0] = 666;
// output second array to check
console.log(b)
// [1,2,3,4,5] OK!
you can use this concept:
firstArray=firstArray.concat(...secondArray);
I want to merge the oldData and newData. Need to show output by sorting date as ascending. If data is available in both, add as [date , oldValue , New value]. If data available in newData only then create like [ '2018-03-30', null, 5 ]
var oldData = [ [ '2018-04-01', 10 ], [ '2018-04-02', 20 ], [ '2018-04-03', 30 ] ];
var newData = [ [ '2018-03-30', 5 ], [ '2018-03-31', 6 ], [ '2018-04-01', 22 ] ];
The desired output would be:
[ [ '2018-03-30', null, 5 ], [ '2018-03-31', null, 6 ], [ '2018-04-01', 10, 22 ] , [ '2018-04-02', 20, null ] , [ '2018-04-03', 30, null ] ];
Please help me achieve this in jquery / java-script.
I'd do something like that:
let output = [];
oldData.map(e => output.push([new String(e[0]), e[1], null]));
for(const elem of newData) {
output.map(e => {
if(e[0] === elem[0]) {
e[2] = elem[1];
continue;
}
})
output.push([new String(elem[0]), null, elem[1]]);
}
You create new array with the values from the oldData, in a desired structure (I user new String() to make sure I don't just copy a reference - remove if not needed).
Then you loop over the elements of newData to see if ouptut already has an elem. with that date.
If so, you change the null inside it to a number from coresponding element.
If not, you just push a new one with given date, null and a number.
Remeber that this will work properly only when the items are unique!
I'm working with this structure:
[
[
{
"comments":"asd",
"movement":"Back Squat",
"userID":"wDHZv3OL55SIymHkhMUejNleNkx1",
"weight":"330"
}
],
[
{
"comments":"asd",
"movement":"Bench Press",
"userID":"wDHZv3OL55SIymHkhMUejNleNkx1",
"weight":"100"
}
],
[
{
"comments":"Comment",
"movement":"Clean",
"userID":"wDHZv3OL55SIymHkhMUejNleNkx1",
"weight":"195"
}
],
[
],
[
],
[
{
"comments":"Front squat comment alpha",
"movement":"Front Squat",
"userID":"wDHZv3OL55SIymHkhMUejNleNkx1",
"weight":"315"
}
],
[
],
[
],
[
],
[
],
[
],
[
{
"comments":"abc",
"movement":"Strict Press",
"userID":"wDHZv3OL55SIymHkhMUejNleNkx1",
"weight":"155"
}
]
]
This is the input I'm using in JSON format. As you can see there are multiple empty arrays.
How would I go about filtering through these arrays and remove the empty ones?
Use the native Array#filter or lodash's _.filter(), and keep the sub arrays with length other than 0.
Array#filter
var arrs = [[{"comments":"asd","movement":"Back Squat","userID":"wDHZv3OL55SIymHkhMUejNleNkx1","weight":"330"}],[{"comments":"asd","movement":"Bench Press","userID":"wDHZv3OL55SIymHkhMUejNleNkx1","weight":"100"}],[{"comments":"Comment","movement":"Clean","userID":"wDHZv3OL55SIymHkhMUejNleNkx1","weight":"195"}],[],[],[{"comments":"Front squat comment alpha","movement":"Front Squat","userID":"wDHZv3OL55SIymHkhMUejNleNkx1","weight":"315"}],[],[],[],[],[],[{"comments":"abc","movement":"Strict Press","userID":"wDHZv3OL55SIymHkhMUejNleNkx1","weight":"155"}]];
var result = arrs.filter(function(sub) {
return sub.length;
});
console.log(result);
Lodash's _.filter() with _.size:
var arrs = [[{"comments":"asd","movement":"Back Squat","userID":"wDHZv3OL55SIymHkhMUejNleNkx1","weight":"330"}],[{"comments":"asd","movement":"Bench Press","userID":"wDHZv3OL55SIymHkhMUejNleNkx1","weight":"100"}],[{"comments":"Comment","movement":"Clean","userID":"wDHZv3OL55SIymHkhMUejNleNkx1","weight":"195"}],[],[],[{"comments":"Front squat comment alpha","movement":"Front Squat","userID":"wDHZv3OL55SIymHkhMUejNleNkx1","weight":"315"}],[],[],[],[],[],[{"comments":"abc","movement":"Strict Press","userID":"wDHZv3OL55SIymHkhMUejNleNkx1","weight":"155"}]];
var result = _.filter(arrs, _.size);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
If all the items in the top level array are arrays then you could lodash's reject with the isEmpty predicate.
let result = _.reject(data, _.isEmpty);
isEmpty will also return true for empty objects amongst other thing so if your top level array can contain such items then to just remove empty arrays you could compose a new function to return just empty arrays and use that as the predicate to reject:
let isEmptyArray = item => _.isArray(item) && _.isEmpty(item);
let result = _.reject(data, isEmptyArray);
Test each array in turn to see if it has a non-zero (truthy) length. If it does, put it in your new array.
var array_of_arrays = [[1], [1,1], [], [], [1]];
var array_of_non_empty_arrays = array_of_arrays.filter((array) => array.length);
console.log(array_of_non_empty_arrays);
hi pretty new to javascript.I am pretty confused in spliting my array value
console.log(arr)//[ [ [ 10, 0 ] ], [ [ 8, 0 ] ], [ [ 8, 0 ] ], [ [ 5, 2 ] ] ]
var line = "";
arr.forEach(e => {
e.forEach(f => line += "[" + f.join(",") + "],");
});
console.log(line);//[10,0],[8,0],[8,0],[5,2],
But i want my ouptput like this to do matrix addition
console.log(line);//[[10,0],[8,0],[8,0],[5,2]]
You can use map() for this.
var arr = [ [ [ 10, 0 ] ], [ [ 8, 0 ] ], [ [ 8, 0 ] ], [ [ 5, 2 ] ] ];
var result = arr.map(function(a) {
return a[0];
});
console.log(result)
You could do this by changing where the join happens and pre/app-ending some square brackets, e.g.
var line = arr.map(e => e.map(f => f.join(",")));
console.log('[' + line.join('],[') + ']');
// [10,0],[8,0],[8,0],[5,2]
I do have to ask though, why are you getting back a set of arrays each with a single value? Is it possible to avoid getting a dataset like that in the first place? You could avoid the double map/foreach that way.
For instance if you had one level less nesting in your source array the map line would become a little simpler
var arr = [ [ 10, 0 ], [ 8, 0 ], [ 8, 0 ], [ 5, 2 ] ];
var line = arr.map(f => f.join(","));
console.log('[' + line.join('],[') + ']');
This is of course if you want to specifically output the string for the array matrix, if you just wanted a flatter version of your original array then you could do:
var newList = arr.map(f => f[0]);
// [ [ 10, 0 ], [ 8, 0 ], [ 8, 0 ], [ 5, 2 ] ]