I just need an idea!
If I have a string "string1, values, string2, values, string3, values, ....."
How can I get the index of the second string? why? because I want divide this string into
"string1, values"
"string2, values"
...
by using substring(0, index-1 of the second string) and so on.
To be more clear I have
""a", 4, 2, 2, 4, 5, "b", 6, 4, 3, 6, 7, "x", 5, 6, 7, 8, .... "
I want the "second" occurrence of a letter
It's not entirely clear to me what you're looking for, maybe this?
str = '"a", 4, 2, 2, 4, 5, "b", 6 4 3 6 7, "x", 5 6 7 8"'
obj = {}, last = ""
str.replace(/(\d+)|(\w+)/g, function(_, d, w) {
d ? obj[last].push(parseInt(d)) : obj[last = w] = []
})
This populates an object obj like this:
{"a":[4,2,2,4,5],"b":[6,4,3,6,7],"x":[5,6,7,8]}
Related
I got a function which receives two numbers (integer), returning an array with the firsts (numbers) multiple of (value) like countBy(value, number).
e.g.
countBy(1, 10) returns [1, 2, 3, 4, 5, 5, 7, 8, 9, 10]
countyBy(2, 5) returns [2, 4, 6, 8, 10]
So, what matcher should be used to test if the function receives only numbers (integer) ?
I did a lot of tests but still did not find a solution.
it ('Verify if are received and returned only numbers', () => {
expect(typeof countBy(2, 5)).toBe('number');
});
Does anybody can give me a light?
try this
const targetArray = [1, 2, 3, 4, 5, 5, 7, 8, 9, 10];
test("Verify if are received and returned only numbers", () => {
targetArray.forEach((target) => {
expect(typeof target).toBe("number");
});
});
I have two arrays, one is an ID array eg.:
fonogramas = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
Array to store informations:
rank_completo = []
and the second is a JSON array eg.:
rank = [ { Tocadas: 1424,
Artista: 'Felipe Araújo',
id_Artista: 1663,
Musica: 'Atrasadinha - Feat. Ferrugem - Ao Vivo',
id_Musica: 44337,
Mes: 1,
Dia: 30,
Tipo_Emissora: 2,
Categoria_Radio: 'FM' },
{ Tocadas: 1356,
Artista: 'Gabriel Diniz',
id_Artista: 1642,
Musica: 'O Nome Dela é Jennifer',
id_Musica: 43158,
Mes: 1,
Dia: 30,
Tipo_Emissora: 2,
Categoria_Radio: 'FM' } ]
I need to map the first array for each ID and find on second array WHERE are they, this below is my code that is bringing -1:
fonogramas.map( ef => {
rank_completo.push(`{ ${rank.map( er => { er.Musica; }).indexOf(ef.id)}, ${ef.id}}`);
});
Thank you!!
EDIT 1:
What I expect is:
rank_completo = [{id: 5, rank: 3},{id: 2, rank: 1},{id:1, rank:2},{id:4, rank: 4}]
EDIT 2: Match example
ef.id = 44337
I have an array with two elements, above those two elements the ef.id is the first one, so my results should be
rank_completo=[{id: 44337, rank: 0}]
You could simply map the rank array with id_Musica and the index of fonogramas' value.
var fonogramas = [1, 2, 3, 44337, 5, 6, 7, 8, 9, 43158],
rank = [ { Tocadas: 1424, Artista: 'Felipe Araújo', id_Artista: 1663, Musica: 'Atrasadinha - Feat. Ferrugem - Ao Vivo', id_Musica: 44337, Mes: 1, Dia: 30, Tipo_Emissora: 2, Categoria_Radio: 'FM' }, { Tocadas: 1356, Artista: 'Gabriel Diniz', id_Artista: 1642, Musica: 'O Nome Dela é Jennifer', id_Musica: 43158, Mes: 1, Dia: 30, Tipo_Emissora: 2, Categoria_Radio: 'FM' }],
rank_completo = rank.map(({ id_Musica }) =>
({ id_Musica, rank: fonogramas.indexOf(id_Musica) }));
console.log(rank_completo);
I think you want this:
rank_completo = rank
.map(
(r, i) => ({
rank: i,
id: r.id_Musica
})
);
I need to find ideal pairing amongst tournament players based on following rules:
players with equal points score or similar should be matched
two players can have only one mutual match in tournament
all players must have a match in a round
Its basically a simplified Swiss tournament system.
I have followings standings:
[{
"playerIndex": 0,
"points": 0,
"opponents": [3, 2, 4]
}, {
"playerIndex": 1,
"points": 3,
"opponents": [4, 5, 2]
}, {
"playerIndex": 2,
"points": 3,
"opponents": [5, 0, 1]
}, {
"playerIndex": 3,
"points": 4,
"opponents": [0, 4, 5]
}, {
"playerIndex": 4,
"points": 6,
"opponents": [1, 3, 0]
}, {
"playerIndex": 5,
"points": 2,
"opponents": [2, 1, 3]
}]
Read as: first array item is player number (index) 0 that already played with players number (index) 3, 2 and 4 and gained 0 points, each item for one of six players in a tournament.
And I need to pick three matches for the fourth match. Following a rule that no two players can play a mutual match more than once I choose from following matches:
[ [ 0, 1 ], [ 0, 5 ], [ 1, 3 ], [ 2, 3 ], [ 2, 4 ], [ 4, 5 ] ]
Each of these six possible matches has a points difference between the two players as follows:
[3, 2, 1, 1, 2, 4]
So ideal pairing for the fourth round that gives each player a match in a round with lowest points difference between paired players is:
[ [0, 5], [1, 3], [2, 4] ]
Is there any way of finding these ideal pairings in real time? It is impossible to try all the possible combinations, because there can be more than 100 people in a tournament and the calculations would take forever.
I have been advised to use https://en.wikipedia.org/wiki/Edmonds%27_algorithm or https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm (both available in JS: https://www.npmjs.com/package/edmonds-blossom and https://github.com/sfentress/edmunds-karp). But I am not sure how to read the results.
Can somebody help please?
Edit: Hungarian algorithm fails if there is too many possible solutions. In my case after first round when there is a lot of players with same amount of points.
Edmond Blossoms algorithm performs much better (found this JS implementation available via NPM https://github.com/mattkrick/EdmondsBlossom).
Just had trouble understanding how to use it. The main difference is that you need to feed it with pairs and the points difference between pairs is higher for the pairs that should be preferred. So I use zero difference for pairs that already played before.
My final (hopefully) solution:
var maxDiff = (roundIndex + 1) * this.config.pointsWin
var possiblePairs = []
availablePlayers.forEach(player => {
availablePlayers.forEach(opponent => {
if (
player.playerIndex !== opponent.playerIndex // &&
// player.opponents.indexOf(opponent.playerIndex) === -1
) {
var match = [player.playerIndex, opponent.playerIndex]
match.sort(function(a, b) {
return a - b;
})
if (player.opponents.indexOf(opponent.playerIndex) === -1) {
match.push(maxDiff - Math.abs(player.points - opponent.points))
}
else {
match.push(0)
}
if (this.searchForArray(possiblePairs, match) === -1) {
possiblePairs.push(match)
}
}
})
})
var rawPairing = edmondsBlossom(possiblePairs)
rawPairing.forEach((match, index) => {
if (match !== -1 && match < index) {
round.matches.push({
home: match,
home_score: '',
away: index,
away_score: '',
referee: -1
})
}
})
First I count max possible points difference amongst players (expecting someone could gain zero points and someone else all of them). Then create all possible combinations between players and mark them with MAX POSSIBLE POINTS - PLAYERS POINTS DIFFERENCE or ZERO for players that matched before.
Then feed the array to EdmondsBlossom function that returns array of integers...
[6,8,14,5,15,3,0,10,1,12,7,13,9,11,2,4]
...read as follows: player index 0 should be paired with player 6, player 1 vs 8, player 2 vs 14, player 3 vs 5... player 5 vs 3 (duplicates). Sometimes there is -1 value in the output that is simply skipped.
Here is my solution (deprecated):
Thanks to #VedPrakash's comment I found the Hungarian algorithm that solves my problem. Luckily there is also a JS implementation available on NPM https://github.com/addaleax/munkres-js.
The Munkers function needs a matrix as input. In my case it is players points difference on intersections of my matrix (see below). The pairs that already played each other have higher value that cant be achieved (9 in my case).
Input matrix:
[ [ 9, 4, 9, 9, 9, 3 ],
[ 4, 9, 9, 2, 9, 9 ],
[ 9, 9, 9, 2, 4, 9 ],
[ 9, 2, 2, 9, 9, 9 ],
[ 9, 9, 4, 9, 9, 5 ],
[ 3, 9, 9, 9, 5, 9 ] ]
Output:
[ [ 0, 5 ], [ 1, 3 ], [ 2, 4 ], [ 3, 1 ], [ 4, 2 ], [ 5, 0 ] ]
The last thing to take care of is filter the Munkers output (that contains duplicates - both pairs 0vs1 and 1vs0) so i filter them simply by comparing first and second index.
My implementation:
var maxDiff = (roundIndex + 1) * this.config.pointsWin
// prepare matrix
var matrix = [];
for (var i = 0; i < availablePlayers.length; i++) {
matrix[i] = new Array(availablePlayers.length);
matrix[i].fill(0)
}
// fill matrix with players points diff
for (var y = 0; y < availablePlayers.length; y++) {
var playerY = availablePlayers[y]
for (var x = 0; x < availablePlayers.length; x++) {
var playerX = availablePlayers[x]
if (x === y) {
matrix[x][y] = maxDiff
}
else if (playerY.opponents.indexOf(x) !== -1) {
matrix[x][y] = maxDiff
matrix[y][x] = maxDiff
}
else {
var value = Math.abs(playerX.points - playerY.points)
matrix[x][y] = value
matrix[y][x] = value
}
}
}
// console.table(matrix)
// console.table(computeMunkres(matrix))
// return
// make pairing
var rawPairing = computeMunkres(matrix)
rawPairing.forEach(pairing => {
if (pairing[0] < pairing[1]) {
round.matches.push({
home: pairing[0],
home_score: '',
away: pairing[1],
away_score: '',
referee: -1
})
}
})
What's the best way to find the index of an array in a collection of arrays? Why doesn't indexOf() return the correct index? I'm guessing it's something to do with object equality?
I've seen other solutions loop through the collection and return the index reached when the equality check is met, but I'm still curious as to why indexOf() doesn't do the same thing. Additionally I can't use ES6's find / findIndex due to IE 11 support (as always). I've included my test code below. Many thanks.
var numbers = [ [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12] ];
function getIndex (numbersToTest) {
return numbers.indexOf(numbersToTest);
};
function test() {
console.log( getIndex( [1, 2, 3, 4, 5, 6] ) ); // Except 0
console.log( getIndex( [7, 8, 9, 10, 11, 12] ) ); // Expect 1
console.log( getIndex( [2, 1, 3, 4, 5, 6] ) ); // Expect -1 (not in same order)
}
test();
Object references (including array references) are compared as reference values; one object reference is equal to another only if both references are to the exact same object. Comparison is not performed based on the content of the arrays, in your case. Even though those arrays you pass in have the same values, they're distinct arrays, and so are not equal to any of the arrays in the original list.
Instead, you need to use something like Array#find (to find the entry) or Array#findIndex (to find the entry's index), passing in a callback that compares the array in numbers with numbersToTest to see if they're equivalent arrays. This question's answers talk about various ways to efficiently compare arrays for equivalence.
For example:
var numbers = [ [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12] ];
function getIndex (numbersToTest) {
return numbers.findIndex(function(entry) {
// Simple comparison that works for an array of numbers
return entry.length === numbersToTest.length && entry.every(function(number, index) {
return numbersToTest[index] === number;
});
});
};
function test() {
console.log( getIndex( [1, 2, 3, 4, 5, 6] ) ); // Expect 0
console.log( getIndex( [7, 8, 9, 10, 11, 12] ) ); // Expect 1
console.log( getIndex( [2, 1, 3, 4, 5, 6] ) ); // Expect -1 (not in same order)
}
test();
Note that both Array#find and Array#findIndex are newish (ES2015, aka "ES6"), but can be polyfilled for older JavaScript engines.
This is just out of curiosity, but do any of you have an idea why this code won't work?
[1, 2, 3, 4, 5].forEach(console.log);
// Prints 'Uncaught TypeError: Illegal invocation' in Chrome
On the other hand, this seems to work fine:
[1, 2, 3, 4, 5].forEach(function(n) { console.log(n) });
So... ?
It's worth pointing out that there is a difference in behavior in the implementation of console.log. Under node v0.10.19 you do not get an error; you simply see this:
> [1,2,3,4,5].forEach(console.log);
1 0 [ 1, 2, 3, 4, 5 ]
2 1 [ 1, 2, 3, 4, 5 ]
3 2 [ 1, 2, 3, 4, 5 ]
4 3 [ 1, 2, 3, 4, 5 ]
5 4 [ 1, 2, 3, 4, 5 ]
This is because the callback to forEach is a three-parameter function taking the value, the index, and the array itself. The function console.log sees those three parameters and dutifully logs them.
Under the Chrome browser console, however, you get
> [1,2,3,4,5].forEach(console.log);
TypeError: Illegal invocation
and in this case, bind will work:
> [1,2,3,4,5].forEach(console.log.bind(console));
1 0 [ 1, 2, 3, 4, 5 ]
2 1 [ 1, 2, 3, 4, 5 ]
3 2 [ 1, 2, 3, 4, 5 ]
4 3 [ 1, 2, 3, 4, 5 ]
5 4 [ 1, 2, 3, 4, 5 ]
but there is an alternative way: note that the second parameter to forEach takes the value of this to use in the callback:
> [1,2,3,4,5].forEach(console.log, console)
1 0 [ 1, 2, 3, 4, 5 ]
2 1 [ 1, 2, 3, 4, 5 ]
3 2 [ 1, 2, 3, 4, 5 ]
4 3 [ 1, 2, 3, 4, 5 ]
5 4 [ 1, 2, 3, 4, 5 ]
which works in the Chrome console and node for me. Of course, I'm sure what you want is just the values, so I'm afraid the best solution is, indeed:
> [1,2,3,4,5].forEach(function (e) {console.log(e)});
1
2
3
4
5
Whether node's behavior is a bug, or it simply takes advantage of the fact that console.log is not specified by ECMA is interesting in its own right. But the varying behavior, and the fact that you have to be aware of whether your callback uses this is important and means we have to fall back to direct coding, even if it is verbose thanks to the keyword function.
This works:
[1,2,3,4,5].forEach(console.log.bind(console));
Actually as #SLaks pointed out, console.log seems to be using this internally and when it's passed as a parameter this now refers to the array instance.
The workaround for that is simply:
var c = console.log.bind(console);
[1,2,3,4,5].forEach(c);
I can't say I've seen that syntax, but my guess is because log expects a parameter, being the message/object/etc to log in the console.
in the first example, you are just passing a function reference to forEach, which is fine if your function doesn't expect paramater which make the function behave as expected. In the second example you pass in e and then log it.