I have this array :
[ [ 1, 'a' ], [ 2, 'b' ], [ 1, 'd' ], [ 9, 'e' ], [ 1, 'f' ], [ 11, 'g' ], [ 9, 'h' ], [ 3, 'i' ] ]
and I would like to have :
[ [ 11, 'g' ], [ 9, 'e' ], [ 9, 'h' ], [ 3, 'i' ], [ 2, 'b' ], [ 1, 'a' ], [ 1, 'd' ], [ 1, 'f' ] ]
How can I do that with javascript please ?
I tried sort(), I also tried with sort(compare) with :
function compare(x, y) {
return x - y;
}
You can use .sort() with Array Destructuring like this:
function compare([a], [b]) {
return b - a;
}
Demo:
let a = [ [ 1, 'a' ], [ 2, 'b' ], [ 1, 'd' ], [ 9, 'e' ], [ 1, 'f' ], [ 11, 'g' ], [ 9, 'h' ], [ 3, 'i' ] ];
a.sort(compare);
function compare([a], [b]) {
return b - a;
}
console.log(a);
.as-console-wrapper { max-height: 100% !important; top: 0; }
In case first elements match, you can sort based on 2nd element as well:
function compare([a, c], [b, d]) {
return (b - a) || c.localeCompare(d)
}
Demo:
let a = [ [ 2, 'b' ], [ 1, 'd' ], [ 9, 'e' ], [ 1, 'f' ], [ 11, 'g' ], [ 9, 'h' ], [ 3, 'i' ], [ 1, 'a' ] ];
a.sort(compare);
function compare([a, c], [b, d]) {
return (b - a) || c.localeCompare(d);
}
console.log(a);
.as-console-wrapper { max-height: 100% !important; top: 0 }
You need to compare the first element in the nested array since you want to sort based on that number.
function compare(x, y) {
return y[0] - x[0];
}
var data = [
[1, 'a'],
[2, 'b'],
[1, 'd'],
[9, 'e'],
[1, 'f'],
[11, 'g'],
[9, 'h'],
[3, 'i']
];
function compare(x, y) {
return y[0] - x[0];
}
data.sort(compare);
console.log(data);
In case you want to sort based on second element(secondary sorting in case the first element is same) then use String#localeCompare method for comparing.
function compare(x, y) {
return y[0] - x[0] || x[1].localeCompare(y[0]);
}
var data = [
[2, 'b'],
[1, 'd'],
[9, 'e'],
[1, 'f'],
[1, 'a'],
[11, 'g'],
[9, 'h'],
[3, 'i']
];
function compare(x, y) {
return (y[0] - x[0]) || x[1].localeCompare(y[1]);
}
data.sort(compare);
console.log(data);
Compare the elements based on their first element, which is the number.
var a = [ [ 1, 'a' ], [ 2, 'b' ], [ 1, 'd' ], [ 9, 'e' ], [ 1, 'f' ], [ 11, 'g' ], [ 9, 'h' ], [ 3, 'i' ] ];
a = a.sort((a,b) => {
return b[0] - a[0]
});
console.log(a)
Use sort to compare first element and if first element is same then compare the second element.
arr.sort( (a,b) => (b[0] - a[0]) || (b[1] - a[1]) )
Demo
var arr = [ [ 1, 'a' ], [ 2, 'b' ], [ 1, 'd' ], [ 9, 'e' ], [ 1, 'f' ], [ 11, 'g' ], [ 9, 'h' ], [ 3, 'i' ] ];
arr.sort( (a,b) => (b[0] - a[0]) || (b[1] - a[1]) );
console.log(arr);
Related
how to loop on object and split it by ":" into separate one
{
labs: [1,2,":",3,4],
level: [1,2,":",3,4]
}
Expected Output:
{
labs: [1,2],
level: [1,2]
}
{
labs: [3,4],
level : [3,4]
}
You can use itertools.groupby from the standard library to group the numbers that are not ":". With that you can use zip to pair off the groups.
from itertools import groupby
d = {
"labs": [1,2,":",3,4],
"level": [10,20,":",30,40]
}
groups = [[(k, list(g)) for b, g in groupby(v, key=lambda n:n != ':') if b]
for k, v in d.items()
]
list(map(dict, zip(*groups)))
# [
# {'labs': [1, 2], 'level': [10, 20]},
# {'labs': [3, 4], 'level': [30, 40]}
# ]
This should work with arbitrary data. For example with input like:
d = {
"labs": [1,2,":",3,4,":", 5, 6],
"level": [10,20,":",30,40,":",50, 60],
"others":[-1,-2,":",-3,-4,":",-5,-6]
}
You will get:
[{'labs': [1, 2], 'level': [10, 20], 'others': [-1, -2]},
{'labs': [3, 4], 'level': [30, 40], 'others': [-3, -4]},
{'labs': [5, 6], 'level': [50, 60], 'others': [-5, -6]}
]
But it does expect the lists to be the same length because the way zip() works. If that's not a good assumption you will need to decide what to do with uneven lists. In that case itertools.zip_longest() will probably be helpful.
Use javaScript to resolve this problem, maybe the code is not the best
const obj = {
labs: [1,2,":",3,4,":",5,6],
level: [1,2,":",3,4,":",7,8],
others: [1,2,":",3,4,":",9,10]
}
const format = (obj = {}, result = []) => {
const keys = Object.keys(obj);
for ( key of keys) {
const itemValues = obj[key].toString().split(':');
let tempRes = {}
itemValues.map((itemValue, index) => {
Object.assign(tempRes, {
[`${keys[index]}`]: itemValue.replace(/^(,)+|(,)+$/g, '').split(',').map(Number)// you can format value here
})
})
result.push(tempRes);
}
return result;
}
console.log(format(obj))
You will get
[
{ labs: [ 1, 2 ], level: [ 3, 4 ], others: [ 5, 6 ] },
{ labs: [ 1, 2 ], level: [ 3, 4 ], others: [ 7, 8 ] },
{ labs: [ 1, 2 ], level: [ 3, 4 ], others: [ 9, 10 ] }
]
I am trying to convert a function written in Javascript to PHP, but even though it is written the same and receiving the same input data it returns different results.
A little context. I am working on creating play days for a tournament in a dynamic way. The input data represents the clashes that will take place between the teams throughout the tournament
Thus
Given the following data
combinations = [
[ 'A', 'B' ], [ 'A', 'C' ],
[ 'A', 'D' ], [ 'B', 'C' ],
[ 'B', 'D' ], [ 'C', 'D' ],
[ 'C', 'D' ], [ 'B', 'D' ],
[ 'B', 'C' ], [ 'A', 'D' ],
[ 'A', 'C' ], [ 'A', 'B' ],
[ 'A', 'B' ], [ 'A', 'C' ],
[ 'A', 'D' ], [ 'B', 'C' ],
[ 'B', 'D' ], [ 'C', 'D' ]
]
Javascript
const getMatches = (combinations) => {
let matches = [];
let i = 0;
while (combinations.length) {
for (const [index, combination] of combinations.entries()) {
if (combinations.length === 1) {
matches[i - 1].push(combination);
combinations.splice(index, 1);
break;
}
if (index === 0) {
matches.push([combination]);
combinations.splice(index, 1);
continue;
}
const [team1, team2] = combination;
const idx = matches[i].findIndex((match) => {
return match.includes(team1) || match.includes(team2);
});
if (idx !== -1) {
continue;
}
matches[i].push(combination);
combinations.splice(index, 1);
}
i++;
}
return matches;
};
PHP
function get_matches ($combinations) {
$matches = [];
$i = 0;
while (count($combinations)) {
foreach ($combinations as $index => $combination) {
if (count($combinations) === 1) {
array_push($matches[$i - 1], $combination);
array_splice($combinations, $index, 1);
break;
}
if ($index === 0) {
array_push($matches, [$combination]);
array_splice($combinations, $index, 1);
continue;
}
$idx = find_index($matches[$i], $combination);
if ($idx !== -1) {
continue;
}
array_push($matches[$i], $combination);
array_splice($combinations, $index, 1);
}
$i++;
}
return $matches;
}
Helper function in PHP
function find_index ( $matches, $teams ) {
[$team1, $team2] = $teams;
foreach ( $matches as $index => $match ) {
if (in_array($team1, $match) || in_array($team2, $match)) {
return $index;
}
}
return -1;
}
Expected output, I am getting this in Javascript
[
[ [ 'A', 'B' ], [ 'C', 'D' ] ],
[ [ 'A', 'C' ], [ 'B', 'D' ] ],
[ [ 'A', 'D' ], [ 'B', 'C' ] ],
[ [ 'B', 'C' ], [ 'A', 'D' ] ],
[ [ 'C', 'D' ], [ 'A', 'B' ] ],
[ [ 'B', 'D' ], [ 'A', 'C' ] ],
[ [ 'A', 'C' ], [ 'B', 'D' ] ],
[ [ 'A', 'B' ], [ 'C', 'D' ] ],
[ [ 'A', 'D' ], [ 'B', 'C' ] ]
]
PHP output
[
[["A","B"],["C","D"]],
[["A","C"],["B","D"]],
[["A","D"],["B","C"]],
[["B","C"],["A","D"]],
[["B","D"],["A","C"]],
[["B","C"],["A","D"]],
[["A","D"],["B","C"]],
[["A","B"],["C","D"]],
[["A","C"],["C","D"]],
[["B","C"],["C","D"]]
]
The result of PHP has the following errors, first instead of returning an array of 9 items it returns 10, second in item 10 and 9 the team C would play twice at the same time
update 0
The logic of the function is implemented following the advice in this answer, specifically paragraphs 1 to 4
Thanks in advance for the time
Hi and I'm new to JavaScripts and hopefully anyone of you would help me to figure out. Thanks
My question is how to write a function that expects an array which could contain strings and/or numbers (as well as finite levels of nested arrays of strings and/or numbers), and returns an object which shows the total number of occurences of each unique values.
function functionName() {
const inputArray = [ 2, 5, 2, 'a', [ 'd', 5, 2, ['b', 1], 0 ], 'A', 5, 'b', 2, 'd' ];
const outputResult = functionName(inputArray);
}
The key in the object is the unique values found in the array, and the value for each key is the number of occurences for each unique key
The expected result I want is :
{
'2': 4,
'5': 3,
'a': 1,
'd': 2,
'b': 2,
'1': 1,
'0': 1,
'A': 1,
}
You can try:
const inputArray = [ 2, 5, 2, 'a', [ 'd', 5, 2, ['b', 1], 0 ], 'A', 5, 'b', 2, 'd' ];
const result = inputArray.flat(Infinity).reduce((acc, item) => (acc[item] = (acc[item] || 0) + 1, acc), {})
console.log(result)
You need to recursiely get occurences of each value, like implemented in calculateOccurences:
const calculateOccurences = function(inputArray, outputResult){
inputArray.forEach(function(value){
if(typeof(value)==='number' || typeof(value)==='string'){
outputResult[value] = outputResult[value] ? outputResult[value]+1 : 1;
}else if (Array.isArray(value)){
calculateOccurences(value, outputResult);
}
})
}
const inputArray = [ 2, 5, 2, 'a', [ 'd', 5, 2, ['b', 1], 0 ], 'A', 5, 'b', 2, 'd' ];
const outputResult = {}
calculateOccurences(inputArray, outputResult );
console.log(outputResult);
Assuming that numbers would be present in type number and not string or that 2 and '2' should be treated the same while calulating occurences.
In this case it's easier if you convert array into string.
var input = [ 2, 5, 2, 'a', [ 'd', 5, 2, ['b', 1], 0 ], 'A', 5, 'b', 2, 'd' ];
//conver intput into string and replace ',' characters
var stringInput = input.toString().replace(/,/g,'');
var output = {};
//counting
for (var i = 0; i < stringInput.length; i++) {
var element = stringInput[i];
output[element] = output[element] ? output[element] + 1 : 1;
}
console.log(output);
The code in python is:
def trimTree(tree):
p=tree[1]
if type(p) == type(""): return p
else :
return(trimTree(p[0]),trimTree(p[1]))
where tree is:
[
13,
[ 6, [ 3, [Object], [Object] ], [ 3, 'a' ] ],
[ 7, [ 3, 'b' ], [ 4, [Object], [Object] ] ]
]
when I convert I got error:
TypeError: Cannot read property '0' of undefined
What should I do?
With a proper data structure, which means any node has only a length of two elements, you get a list of values in breaths first order (the result is here a string).
function trimTree(tree) {
var p = tree[1];
return typeof p === 'string'
? p
: trimTree(p[0]) + trimTree(p[1]);
}
var data = [
13,
[
[6,
[
[3,
[
[1, 'X'],
[2, 'Y']
]
],
[3, 'a']
]
],
[7,
[
[3, 'b'],
[4,
[
[2, 'Z'],
[2, 'Q']
]
]
]
]
]
];
console.log(trimTree(data));
I am trying to write a function to flatten an array. I have part of the function working and I need help in the other half.
flatten: function(anyArray, singleLevel) {
if (singleLevel == true) {
flatArray = Array.prototype.concat.apply([], anyArray);
return flatArray;
}
flatArray = Array.prototype.concat.apply([], anyArray);
if (flatArray.length != anyArray.length) {
flatArray = someObject.array.flatten(flatArray);
}
return flatArray;
}
if I type
.flatten([[[1],[1,2,3,[4,5],4],[2,3]]], true);
I want it to flatten only one level:
[[1],[1,2,3,[4,5],4],[2,3]]
Modern JavaScript allows us to handle this very easily using a variety of techniques
Using Array.prototype.flat -
const arr =
[ [ 1 ], [ 2, 3, [ 4, 5, [ 6 ] ] ], [ 7, [ 8, 9 ] ] ]
const flatArr =
arr.flat(1) // 1 is default depth
console.log(JSON.stringify(arr))
console.log(JSON.stringify(flatArr))
// [[1],[2,3,[4,5,[6]]],[7,[8,9]]]
// [1,2,3,[4,5,[6]],7,[8,9]]
Using Array.prototype.flatMap -
const arr =
[ [ 1 ], [ 2, 3, [ 4, 5, [ 6 ] ] ], [ 7, [ 8, 9 ] ] ]
const flatArr =
arr.flatMap(x => x)
console.log(JSON.stringify(arr))
console.log(JSON.stringify(flatArr))
// [[1],[2,3,[4,5,[6]]],[7,[8,9]]]
// [1,2,3,[4,5,[6]],7,[8,9]]
Using a spread argument to Array.prototype.concat
const arr =
[ [ 1 ], [ 2, 3, [ 4, 5, [ 6 ] ] ], [ 7, [ 8, 9 ] ] ]
const flatArr =
[].concat(...arr)
console.log(JSON.stringify(arr))
console.log(JSON.stringify(flatArr))
// [[1],[2,3,[4,5,[6]]],[7,[8,9]]]
// [1,2,3,[4,5,[6]],7,[8,9]]
Older version of JavaScript (ECMAScript 5 and below) can use techniques like Function.prototype.apply -
var arr =
[ [ 1 ], [ 2, 3, [ 4, 5, [ 6 ] ] ], [ 7, [ 8, 9 ] ] ]
var flatArr =
Array.prototype.concat.apply([], arr)
console.log(JSON.stringify(arr))
console.log(JSON.stringify(flatArr))
// [[1],[2,3,[4,5,[6]]],[7,[8,9]]]
// [1,2,3,[4,5,[6]],7,[8,9]]
Using Array.prototype.reduce -
var arr =
[ [ 1 ], [ 2, 3, [ 4, 5, [ 6 ] ] ], [ 7, [ 8, 9 ] ] ]
var flatArr =
arr.reduce((r, a) => r.concat(a), [])
console.log(JSON.stringify(arr))
console.log(JSON.stringify(flatArr))
// [[1],[2,3,[4,5,[6]]],[7,[8,9]]]
// [1,2,3,[4,5,[6]],7,[8,9]]
Using a primitive for loop -
var arr =
[ [ 1 ], [ 2, 3, [ 4, 5, [ 6 ] ] ], [ 7, [ 8, 9 ] ] ]
var flatArr =
[]
for (var i = 0; i < arr.length; i = i + 1)
flatArr = flatArr.concat(arr[i])
console.log(JSON.stringify(arr))
console.log(JSON.stringify(flatArr))
// [[1],[2,3,[4,5,[6]]],[7,[8,9]]]
// [1,2,3,[4,5,[6]],7,[8,9]]
The concat array method expects one or more arrays as arguments, whose elements will be appended:
[1].concat([2, 3], [4]) // [1, 2, 3, 4]
So if you are using apply, that will flatten another level:
[].concat.apply([1], [[2], [3]]) // === [1].concat([2], [3])
So you can either use push instead of concat, or call (or just direct invocation) instead of apply to get only a single flattening level.
if you use ES6/ES2015 you can use spread operator. Something like this
console.log(...[[[1],[1,2,3,[4,5],4],[2,3]]])