I am trying to convert a function of python code into JavaScript.
The arr variable is an array such as [2, 5, 3, 1]. Basically, I want to create a list of tuple where each tuple contains as first value the position of the element in the arr and as second value the element of the arr. Then, I want to do the same for the reversed of arr
Python code:
def myPositions(arr):
positions = sorted(list(enumerate(arr)), key=lambda e: e[1])
return positions
def final(arr):
print("Reversed", arr[::-1]) # [ 1, 3, 5, 2 ]
print(myPositions(arr)) # [(3, 1), (0, 2), (2, 3), (1, 5)]
print(myPositions(arr[::-1])) # [(0, 1), (3, 2), (1, 3), (2, 5)]
My JavaScript code
Since there is no enumerate in JavaScript (this is what I think), I did the following:
function myPositions(arr) {
let positions = arr.map((e,i) => [i, e]).sort((a, b) => a[1] - b[1] )
return positions
}
function final(arr) {
let reversedArr = arr.reverse()
console.log("Reversed", reversedArr) // [ 1, 3, 5, 2 ]
let x = myPositions(arr)
console.log(x) // [ [ 0, 1 ], [ 3, 2 ], [ 1, 3 ], [ 2, 5 ] ]
let y = myPositions(reversedArr)
console.log(y) // [ [ 0, 1 ], [ 3, 2 ], [ 1, 3 ], [ 2, 5 ] ] This is different than print(myPositions(arr[::-1]))
}
I do not get why it works the same if I do not reverse the array.
But with the reversed array, I get two different results.
In python I get [(0, 1), (3, 2), (1, 3), (2, 5)], in JS I get [ [ 0, 1 ], [ 3, 2 ], [ 1, 3 ], [ 2, 5 ] ]
Related
So I have this 2D permutations array of ints which looks like this:
arr = [
[ 5, 2, 6 ],
[ 2, 5, 6 ],
[ 6, 5, 2 ],
[ 5, 6, 2 ],
[ 2, 6, 5 ],
[ 6, 2, 5 ]
]
and essentially I want to be able to get a string that looks like this '652,625,562,526,256'
This means that the numbers are ordered and are in string format.
What I have done so far is:
arr.map(c => c.join("")).join()
Which combines it to a array, however now my thought process would be to convert this to a array of ints and then order and re-parse as strings, but there must be some kind of easier way to do this?
I'm quite new to JavaScript so any help is appreciated.
Don't do the second join immediately - instead, sort the array of joined strings first, then join:
const arr = [
[ 5, 2, 6 ],
[ 2, 5, 6 ],
[ 6, 5, 2 ],
[ 5, 6, 2 ],
[ 2, 6, 5 ],
[ 6, 2, 5 ]
];
const result = arr
.map(subarr => subarr.join(''))
.sort((a, b) => b.localeCompare(a, undefined, { numeric: true }))
.join();
console.log(result);
or map to numbers and subtract in the comparator:
const arr = [
[ 5, 2, 6 ],
[ 2, 5, 6 ],
[ 6, 5, 2 ],
[ 5, 6, 2 ],
[ 2, 6, 5 ],
[ 6, 2, 5 ]
];
const result = arr
.map(subarr => Number(subarr.join('')))
.sort((a, b) => b - a)
.join();
console.log(result);
I am trying to use a priority Queue for my own data type which is a 3x3 array. The actual code and data type is more complex so I boiled it down to the essentials. Note that the priority queue works well for an integer data type (see output at the end). Everything is self explanatory. Assume the metric function returns a positive integer for a given 3X3 array. I am confused why the dequeueing from the heap does not return the min valued object (or max valued in case I got the comparator backwards but I got the middle value for both). For the data type of integer the priority Queue seems to work correctly as the output shows.
var r = require('js-priority-queue');
metric = function (A) {
N = A.length;
if (A[0][1] == 0) return 123;
if (A[0][1] == 5) return 124;
if (A[0][1] == 1) return 122;
if (A[0][1] == 6) return 122;
return 0;
}
mComparator = function (m1, m2) {
ret = metric(m2) - metric(m1);
return ret;
}
mHeap = new r(mComparator);
nHeap = new r(function (a,b) {
return b - a;
})
A = [[5, 0, 1], [7, 6, 3], [2, 4, 8]];
B = [[5, 6, 1], [7, 0, 3], [2, 4, 8]];
C = [[5, 1, 0], [7, 6, 3], [2, 4, 8]];
D = [[0, 5, 1], [7, 6, 3], [2, 4, 8]];
console.log("metric(A) -> %d", metric(A));
console.log("metric(B) -> %d", metric(B));
console.log("metric(C) -> %d", metric(C));
console.log("metric(D) -> %d", metric(D));
mHeap.queue(A);
mHeap.queue(B);
mHeap.queue(C);
mHeap.queue(D);
X = mHeap.dequeue();
console.log(X);
X = mHeap.dequeue();
console.log(X);
X = mHeap.dequeue();
console.log(X);
X = mHeap.dequeue();
console.log(X);
nHeap.queue(123);
nHeap.queue(124);
nHeap.queue(122);
nHeap.queue(122);
y = nHeap.dequeue();
console.log(y);
#Output
metric(A) -> 123
metric(B) -> 122
metric(C) -> 122
metric(D) -> 124
[ [ 5, 0, 1 ], [ 7, 6, 3 ], [ 2, 4, 8 ] ]
[ [ 0, 5, 1 ], [ 7, 6, 3 ], [ 2, 4, 8 ] ]
[ [ 5, 1, 0 ], [ 7, 6, 3 ], [ 2, 4, 8 ] ]
[ [ 5, 6, 1 ], [ 7, 0, 3 ], [ 2, 4, 8 ] ]
122
If you are using the adamhooper priority queue, then your problem is you are not supplying the comparator correctly. Change your constructor invocations to:
mHeap = new r({"comparator": mComparator});
nHeap = new r({"comparator": function (a,b) {
return b - a;
}})
And you should start getting expected results. Note that this gives you max-heaps. Since you wanted min-heaps, you should also reverse your comparison order:
mComparator = function (m1, m2) {
ret = metric(m1) - metric(m2);
return ret;
}
mHeap = new r({"comparator": mComparator});
nHeap = new r({"comparator": function (a,b) {
return a - b;
}})
Example code for correctly supplying a comparator is given on the github project's front page, but I see how it could be easy to miss.
I have a multidimensional array which contains arrays of different lengths.
I want to average the corresponding index values of all the arrays.
For arrays that don't have the index won't be considered when averaging the values.
var multiArray = [
[4, 1, 3],
[6, 4, 2, 3, 4],
[8, 6, 1, 2],
[2, 3]
];
var avgIdxArray = [];
// logic helper
// (4 + 6 + 8 + 2) / 4 = 5
// (1 + 4 + 6 + 3) / 4 = 3.5
// (3+ 2 +1) / 3 = 2
// (3 + 2) / 5 = 2.5
// 4 / 1 = 4;
// (sum of index values) / number of arrays that have those index
// desired output
console.log(avgIdxArray);
// [5, 3.5 ,2 ,2.5 ,4]
Can it be achieved using the .map(), .filter() and .reduce() method? Also what could be the most efficient way of handling this problem?
One solution is this:
1- Convert multiArray array to its vertical type (New array with their indexes as you said in question)
2- Calculate sum and then avg of each array.
var multiArray = [
[4, 1, 3],
[6, 4, 2, 3, 4],
[8, 6, 1, 2],
[2, 3]
],
target = [];
multiArray.map((itm) => {
let x = Object.keys(itm);
x.forEach((ii) => {
if (target.length <= ii) {
target.push([]);
}
target[ii].push(itm[ii])
});
});
target.forEach((arr)=> {
let sum = arr.reduce(function(a, b) { return a + b; });
let avg = sum / arr.length;
console.log(avg)
})
Iterate the array with Array.reduce(). Iterate the sub array with Array.forEach(), and collect the sum, and the amount of items in the index. Use Array.map() to convert each sum/count object to average:
const multiArray = [
[4, 1, 3],
[6, 4, 2, 3, 4],
[8, 6, 1, 2],
[2, 3]
];
const result = multiArray
.reduce((r, a) => {
a.forEach((n, i) => {
const { sum = 0, count = 0 } = r[i] || {};
r[i] = { sum: sum + n, count: count + 1 };
});
return r;
}, [])
.map(({ sum, count }) => sum / count);
console.log(result);
Pure mapreduce.
Object.keys(multiArray.sort( (x,y) => y.length - x.length)[0]).
map( x => Object.keys(multiArray).
map(y => x < multiArray[y].length?multiArray[y][x]:undefined)).
map( a => ({sum: (a.reduce((l,r) => (l?l:0) + (r?r:0))), length: (a.filter(x => x).length)}) ).
map( pair => pair.sum / pair.length)
Output
[ 5, 3.5, 2, 2.5, 4 ]
A lot going there. Lets take it step by step
var multiArray = [
... [4, 1, 3],
... [6, 4, 2, 3, 4],
... [8, 6, 1, 2],
... [2, 3]
... ];
Order the arrays so that the array with the most element becomes first
multiArray.sort( (x,y) => y.length - x.length)
[ [ 6, 4, 2, 3, 4 ], [ 8, 6, 1, 2 ], [ 4, 1, 3 ], [ 2, 3 ] ]
Take the first element and loop over its keys. This is the largest element as we have sorted it before.
Object.keys(multiArray.sort( (x,y) => y.length - x.length)[0])
[ '0', '1', '2', '3', '4' ]
Now check if all the arrays have that key, else put an undefined over there
Object.keys(multiArray.sort( (x,y) => y.length - x.length)[0]).
map( x => Object.keys(multiArray).
map(y => x < multiArray[y].length?multiArray[y][x]:undefined)).
[ [ 6, 8, 4, 2 ],
[ 4, 6, 1, 3 ],
[ 2, 1, 3, undefined ],
[ 3, 2, undefined, undefined ],
[ 4, undefined, undefined, undefined ] ]
Create an object with sum and length. This part is optional, but I wanted this to be clear
Object.keys(multiArray.sort( (x,y) => y.length - x.length)[0]).
map( x => Object.keys(multiArray).
map(y => x < multiArray[y].length?multiArray[y][x]:undefined)).
map( a => ({sum: (a.reduce((l,r) => (l?l:0) + (r?r:0))), length: (a.filter(x => x).length)}) )
[ { sum: 20, length: 4 },
{ sum: 14, length: 4 },
{ sum: 6, length: 3 },
{ sum: 5, length: 2 },
{ sum: 4, length: 1 } ]
Finally get the avg
Object.keys(multiArray.sort( (x,y) => y.length - x.length)[0]).
map( x => Object.keys(multiArray).
map(y => x < multiArray[y].length?multiArray[y][x]:undefined)).
map( a => ({sum: (a.reduce((l,r) => (l?l:0) + (r?r:0))), length: (a.filter(x => x).length)}) ).
map( pair => pair.sum / pair.length)
[ 5, 3.5, 2, 2.5, 4 ]
I am trying to push values into a multidimensional array and read values out of it based on code that i've seen on other posts on this site. This is my array push code.
SelectedWindowGraphs.push([ContainerIDValue,elementID+"chkbox"]);
ContainerIDValue is an integer and elementID+"chkbox" is what i want to store at that position in the array. Here is what i saw when i debugged my code:
This is not what i want. At position 0, i want CUT17chkbox, CUT18chkbox, and CUT19chkbox. How do i fix my array so that i does that?
// initialize an array at that position in case it has not been defined yet
SelectedWindowGraphs[ContainerIDValue] = (SelectedWindowGraphs[ContainerIDValue] ||
[]);
// push the value at the desired position
SelectedWindowGraphs[ContainerIDValue].push(elementID+"chkbox");
You have to push to a subarray:
if(!SelectedWindowGraphs[ContainerIDValue])
SelectedWindowGraphs[ContainerIDValue] = [];
SelectedWindowGraphs[ContainerIDValue]
.push(elementID+"chkbox");
You could add elements at certain position just doing:
var arr = [ 1, 2, 3, 4, 5, 6, 7 ]
arr[2] = "three";
console.log(arr);//[ 1, 2, 'three', 4, 5, 6, 7 ]
In a multidimensional array:
var arr = [ 1, [2, 3, 4, 5, 6], 7 ]
arr[1][2] = "four";
console.log(arr);//[ 1, [ 2, 3, 'four', 5, 6 ], 7 ]
When you perform push you are adding one or more elements at the end.
var arr = [1,2,3]
arr.push(4,5);//you are adding 4 and then 5
console.log(arr);//[ 1, 2, 3, 4, 5 ]
In a multidimensional array:
var arr = [1,2,[3,4]]
arr[2].push(5,6);//position 2
console.log(arr);//[ 1, 2, [ 3, 4, 5, 6 ] ]
To insert an element in a specific position (and move right element n positions) you could use splice(). In the following case, 2th and 3th position
var arr = [ 1, 2, 3, 4, 5 ]
arr.splice(2, 0, 999, 8888);
console.log(arr);//[ 1, 999, 8888, 2, 3, 4, 5 ]
In a multidimensional array:
var arr = [ 1, 2, [3,4,5], 6, 7 ]
arr.splice(2, 0, [8,9,10]);
console.log(arr);//[ 1, 2, [ 8, 9, 10 ], [ 3, 4, 5 ], 6, 7 ]
I have the following:
a = {x:1, y:3, w:4}
b = {c:2, d:3}
And I want to obtain all the values of these objects iterating only once.
result = [1, 3, 4, 2, 3]
I have the following solution but it has multiple iterations.
result = _.chain(a).values().union(_.values(b)).value();
I would like to avoid the "_.values(b)" and do this using the same chain from a.
I also tried this, but it is not working properly:
result = _.chain({}).extend(a,b).values().value();
If you're intent on chaining, then
_.chain([a, b]) . // [ { x: 1, y: 3, w: 4 }, { c: 2, d: 3 } ]
map(_.values) . // [ [ 1, 3, 4 ], [ 2, 3 ] ]
flatten() . // [ 1, 3, 4, 2, 3 ]
uniq() . // [ 1, 3, 4, 2 ]
value()
How about.
var a = {x:1, y:3, w:4},
b = {c:2, d:3};
result = _.values(_.extend(a,b));