I try to make an algorithm visualization project - right now I am implementing visualization of bubble-sort - I've got an array of arrays in which each outer array represents one iteration of the algorithm, and each inner array consists of boolean values - swap or no swap neighboring elements in the collection - I have algorithm ready, and sorting is done correctly, right now I wanted to introduce time delays between each swap - as it is visualization program I want the user to see actually what's going on. Here I stumbled upon a problem - I wanted to use async await with setTimeout but apparently I lack knowledge (I mostly work with java) - columns are not sorted correctly - I would say that setTimeout is incorrectly scheduled in parallel for different iterations, but I am not sure. Code of mine:
async function visualiseAlgorithm(responseFromServer) {
for (const iteration of responseFromServer.data) {
await displayIteration(iteration.swapsRecord);
}
}
async function displayIteration(swapsForIteration) {
let idx = 0;
for (const shouldSwap of swapsForIteration) {
await drawColumns(shouldSwap, idx++).then(res => {
context.clearRect(0, 0, canvas.width, canvas.height);
drawBaseLine();
columnsArray.forEach(column => column.draw());
});
}
}
function drawColumns(toSwap, index){
return new Promise(resolve => setTimeout(() => {
if(index > 1) columnsArray[index - 1].setColor("grey");
let color;
if(toSwap){
color = "red";
let temp = columnsArray[index].getHeight();
columnsArray[index].setHeight(columnsArray[index + 1].getHeight());
columnsArray[index + 1].setHeight(temp);
}
}, 100))
}
Results:
With timeout and async await:
Input:
Output
Without timeout and async await:
Input
Output
As requested: I post response from the server:
Array(37) [ {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, … ]
0: Object { swapsRecord: [], collection: (45) […] }
1: Object { swapsRecord: (44) […], collection: (45) […] }
2: Object { swapsRecord: (44) […], collection: (45) […] }
3: Object { swapsRecord: (44) […], collection: (45) […] }
4: Object { swapsRecord: (44) […], collection: (45) […] }
5: Object { swapsRecord: (44) […], collection: (45) […] }
6: Object { swapsRecord: (44) […], collection: (45) […] }
7: Object { swapsRecord: (44) […], collection: (45) […] }
8: Object { swapsRecord: (44) […], collection: (45) […] }
9: Object { swapsRecord: (44) […], collection: (45) […] }
10: Object { swapsRecord: (44) […], collection: (45) […] }
11: Object { swapsRecord: (44) […], collection: (45) […] }
12: Object { swapsRecord: (44) […], collection: (45) […] }
13: Object { swapsRecord: (44) […], collection: (45) […] }
14: Object { swapsRecord: (44) […], collection: (45) […] }
15: Object { swapsRecord: (44) […], collection: (45) […] }
16: Object { swapsRecord: (44) […], collection: (45) […] }
17: Object { swapsRecord: (44) […], collection: (45) […] }
18: Object { swapsRecord: (44) […], collection: (45) […] }
19: Object { swapsRecord: (44) […], collection: (45) […] }
20: Object { swapsRecord: (44) […], collection: (45) […] }
21: Object { swapsRecord: (44) […], collection: (45) […] }
22: Object { swapsRecord: (44) […], collection: (45) […] }
23: Object { swapsRecord: (44) […], collection: (45) […] }
24: Object { swapsRecord: (44) […], collection: (45) […] }
25: Object { swapsRecord: (44) […], collection: (45) […] }
26: Object { swapsRecord: (44) […], collection: (45) […] }
27: Object { swapsRecord: (44) […], collection: (45) […] }
28: Object { swapsRecord: (44) […], collection: (45) […] }
29: Object { swapsRecord: (44) […], collection: (45) […] }
30: Object { swapsRecord: (44) […], collection: (45) […] }
31: Object { swapsRecord: (44) […], collection: (45) […] }
32: Object { swapsRecord: (44) […], collection: (45) […] }
33: Object { swapsRecord: (44) […], collection: (45) […] }
34: Object { swapsRecord: (44) […], collection: (45) […] }
35: Object { swapsRecord: (44) […], collection: (45) […] }
36: Object { swapsRecord: (44) […], collection: (45) […] }
Objects in the array consists of: (the collection array is redundant and not used - I plan to delete it)
Object { swapsRecord: (44) […], collection: (45) […] }
collection: Array(45) [ 61, 53, 35, … ]
swapsRecord: Array(44) [ false, true, true, … ]
0: false
1: true
2: true
3: false
4: true
5: true
6: true
7: false
8: true
9: true
10: true
11: true
12: true
13: true
14: true
15: true
16: true
17: true
18: true
19: true
20: true
21: true
22: true
23: true
24: true
25: true
26: true
27: true
28: true
29: true
30: true
31: true
32: true
33: true
34: true
35: true
36: true
37: true
38: true
39: true
40: false
41: true
42: true
43: true
length: 44
You need to resolve the promise or it wouldn't do the following stuff. Without it, your loop will stay the first step.
That's the reason why the output is the same as the input.
async function visualiseAlgorithm(responseFromServer) {
for (const iteration of responseFromServer.data) {
await displayIteration(iteration.swapsRecord);
}
}
async function displayIteration(swapsForIteration) {
let idx = 0;
for (const shouldSwap of swapsForIteration) {
await drawColumns(shouldSwap, idx++).then(res => {
context.clearRect(0, 0, canvas.width, canvas.height);
drawBaseLine();
columnsArray.forEach(column => column.draw());
});
}
}
function drawColumns(toSwap, index){
return new Promise(resolve => setTimeout(() => {
if(index > 1) columnsArray[index - 1].setColor("grey");
let color;
if(toSwap){
color = "red";
let temp = columnsArray[index].getHeight();
columnsArray[index].setHeight(columnsArray[index + 1].getHeight());
columnsArray[index + 1].setHeight(temp);
}
// this is the point
resolve()
}, 100))
}
For more information
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
You can add a sleep function like this. And, await it whenever you want a delay. This will avoid the superfluous async and Promise wrappers in existing drawColumns function
// https://stackoverflow.com/a/47092642
async function sleep(sec) {
return new Promise(resolve => setTimeout(resolve, sec));
}
async function visualiseAlgorithm(responseFromServer) {
for (const iteration of responseFromServer.data) {
await displayIteration(iteration.swapsRecord);
}
}
async function displayIteration(swapsForIteration) {
let idx = 0;
for (const shouldSwap of swapsForIteration) {
await sleep(100) // <-- add this whenever you want a delay
drawColumns(shouldSwap, idx++)
context.clearRect(0, 0, canvas.width, canvas.height);
drawBaseLine();
columnsArray.forEach(column => column.draw());
}
}
function drawColumns(toSwap, index) {
if (index > 1) columnsArray[index - 1].setColor("grey");
let color;
if (toSwap) {
color = "red";
let temp = columnsArray[index].getHeight();
columnsArray[index].setHeight(columnsArray[index + 1].getHeight());
columnsArray[index + 1].setHeight(temp);
}
}
Related
For the following array :
const a = [
{
26: [0],
27: [100],
28: [0]
},
{
26: [0],
27: [100],
28: [0]
},
{
26: [0],
27: [100],
28: [0]
}
]
I need a function that should merge arrays with the same keys in the object.
`const result = [{
26: [0,0,0],
27: [100,100,100],
28: [0,0,0]
}]`
Try to use reduce
const data = [{
26: [0], 27: [100], 28: [0]
},
{
26: [0], 27: [100], 28: [0]
},
{
26: [0], 27: [100], 28: [0]
}
];
const restructure = arr =>
[arr.reduce((accumu, current) => {
for (const [key, val] of Object.entries(current)) {
accumu[key] = [...accumu[key] ?? '', ...val];
}
return accumu;
}, {})];
console.log(JSON.stringify(restructure(data)));
You can simply achieve this by using Array.forEach() loop.
Live Demo :
const a = [{
26: [0],
27: [100],
28: [0]
}, {
26: [0],
27: [100],
28: [0]
}, {
26: [0],
27: [100],
28: [0]
}];
let resObj = {};
a.forEach(obj => {
Object.keys(obj).forEach(key => {
resObj[key] ? resObj[key].push(...obj[key]) : resObj[key] = [...obj[key]]
})
});
console.log([resObj]);
Keeping around a collection of utility functions can make this sort of problem nearly trivial to handle.
My solution is to write this function:
const combine = reduce (mergeWith (concat)) ({})
based on my utility functions reduce, concat, and mergeWith. Then it's as simple as:
combine (a) //=> {26: [0, 0, 0], 27: [100, 100, 100], 28: [0, 0, 0]}
const reduce = (f) => (init) => (xs) => xs .reduce ((a, x) => f (a, x), init)
const concat = (a) => (b) => a .concat (b)
const mergeWith = (f) => (a, b) => Object .fromEntries (
[... new Set ([... Object .keys (a), ... Object .keys (b)])] .map (
(k) => [k, k in a ? (k in b ? f (a [k]) (b [k]) : a [k]) : b [k]]
)
)
const combine = reduce (mergeWith (concat)) ({})
const a = [{26: [0], 27: [100], 28: [0]}, {26: [0], 27: [100], 28: [0]}, {26: [0], 27: [100], 28: [0]}]
console .log (combine (a))
.as-console-wrapper {max-height: 100% !important; top: 0}
reduce and concat do little more than convert the Array .prototype methods into pure functions.1 In each case, the new function is fully curried so that, for instance, you would call reduce (tranformer) (initialValue) (values) rather than values .reduce (transformer, initialValue). This style often makes it easier to compose functions.
mergeWith is more involved. It performs a shallow merge of two objects, using the supplied function on the relevant properties of both objects whenever both objects have a given key, and taking the only property supplied otherwise.
Once we have these helper functions in place, then this becomes quite simple to write. We configure mergeWith with concat, and pass this resulting function and the empty object to reduce.
const combine = reduce (mergeWith (concat)) ({})
1reduce does not supply all the parameters to the transformation function that Array.prototype.reduce does. There are good reasons for this, not worth discussing here, but if you wanted them, we could simplify the implementation to just const reduce (f) => (init) => (xs) => xs .reduce (f, init).
This can easily be achieved by using Javascript's inbuilt Array.Prototype.map() method
My solution:
function mergeSameKeys(arr) {
let filteredObj = {}
arr.map(obj => {
let objKeys = Object.keys(obj);
objKeys.map(key => {
if (!filteredObj.hasOwnProperty(key)) {
filteredObj[key] = obj[key]
} else {
filteredObj[key].push(...obj[key])
}
})
})
return [filteredObj]
}
mergeSameKeys([{
26: [0],
27: [100],
28: [0]
},
{
26: [0],
27: [100],
28: [0]
},
{
26: [0],
27: [100],
28: [0]
}
])
// returns [{
// 26: [0,0,0],
// 27: [100,100,100],
// 28: [0,0,0]
// }]
The function loops over every item in the provided array and for every object it gets the names of all the objects keys using Object.keys() and returns them as a list of items in an array stored in objKeys, it then loops over every key name in objKeys and checks if the filteredObj variable contains this key as a property. If this check returns false, it creates a new key in filteredObj using this key name and setting the value of the created key to the value of the key in its original object. If the check happens to be true, it simply pushes the key's value in its original object to the key's value in the filteredObj variable. Using the Spread syntax (...), it pushes the actual value and not the entire array. The function returns the filteredObj variable in an array at the end and voila. Code implementation is finished.
I am trying to count how many times a specific item appears in an array. And then push that amount to an other array. I got the counter working, although when I push this amount to the array the type of this value turn out te be Not A Number...
Here is my code:
res2 =
0: (2) [29682885, "Jean-Paul"]
1: (2) [29682886, "DEMO Martin"]
2: (2) [29682887, "Johan"]
3: (2) [29682892, "Peter"]
4: (2) [29682900, "Antoine"]
5: (2) [29682902, "Sandra"]
6: (2) [29682906, "Kevin"]
7: (2) [29682910, "Wouter"]
8: (2) [29682911, "Tom"]
9: (2) [4, "Autotask"]
res3 =
0: (2) [29682885, "2019-05-16T08:25:32Z"]
1: (2) [29682885, "2019-07-01T13:11:00Z"]
2: (2) [29682885, "2019-07-03T10:21:07Z"]
3: (2) [29682885, "2019-09-03T14:00:45Z"]
4: (2) [29682885, "2019-09-11T09:59:07Z"]
5: (2) [29682885, "2019-09-17T14:13:39Z"]
6: (2) [29682885, "2019-10-09T16:48:41Z"]
7: (2) [29682885, "2019-10-30T13:48:12Z"]
8: (2) [29682885, "2019-10-30T14:13:01Z"]
9: (2) [29682885, "2019-10-30T14:34:13Z"]
10: (2) [29682885, "2019-11-07T13:41:27Z"]
11: (2) [29682885, "2019-11-22T12:41:08Z"]
...
res2.sort();
res3.sort();
res3.forEach(sale => {
res2.forEach(person => {
if (sale[0] === person[0]) {
if (person[1] === undefined) {
person[1] = 1;
console.log(person[1]);
} else {
person[1].occurrences++;
console.log(person[1]);
prepArray.push(person[1]);
}
prepArray.push(person[1]);
}
});
});
prepArray.push(person[1]); retruns an NaN somehow. But the console shows the exact amount I would like to push to my prepArray...
I've used a mix of filter, flat, map to achieve this. Added code comments to explain what logic is being used.
res2 = [[29682885, "Jean-Paul"],
[29682886, "DEMO Martin"],
[29682887, "Johan"],
[29682892, "Peter"],
[29682900, "Antoine"],
[29682902, "Sandra"],
[29682906, "Kevin"],
[29682910, "Wouter"],
[29682911, "Tom"],
[4, "Autotask"]]
res3 = [[29682885, "2019-05-16T08:25:32Z"],
[29682885, "2019-07-01T13:11:00Z"],
[29682902, "2019-07-03T10:21:07Z"],
[29682885, "2019-09-03T14:00:45Z"],
[29682885, "2019-09-11T09:59:07Z"],
[29682885, "2019-09-17T14:13:39Z"],
[29682902, "2019-10-09T16:48:41Z"],
[4, "2019-10-30T13:48:12Z"],
[4, "2019-10-30T14:13:01Z"],
[29682911, "2019-10-30T14:34:13Z"],
[29682911, "2019-11-07T13:41:27Z"],
[29682911, "2019-11-22T12:41:08Z"]];
// pick only the ids from res3
// this makes it easier for comparison
let res = res3.map(v => {
return v.shift();
}).flat()
let final = [];
// loop over res2, and count occurrences using .filter().length
res2.map(sale => final.push([sale[1], res.filter(person => person === sale[0]).length]));
console.log(final);
// if you want the output as an object,
// you can do the following
let finalObj = {};
res2.map(sale => finalObj[sale[1]] = res.filter(person => person === sale[0]).length);
console.log({ finalObj })
I've modified the input set (res3) slightly to show the difference in counts, the above code outputs the following,
[
[
"Jean-Paul",
5
],
[
"DEMO Martin",
0
],
[
"Johan",
0
],
[
"Peter",
0
],
[
"Antoine",
0
],
[
"Sandra",
2
],
[
"Kevin",
0
],
[
"Wouter",
0
],
[
"Tom",
3
],
[
"Autotask",
2
]
]
Edited my answer to get the desired output in object format, so now you'll get,
{
"Jean-Paul": 5,
"DEMO Martin": 0,
"Johan": 0,
"Peter": 0,
"Antoine": 0,
"Sandra": 2,
"Kevin": 0,
"Wouter": 0,
"Tom": 3,
"Autotask": 2
}
I don't understand many parts of your code, but trying to interpretate it:
res2 = [
[29682885, "Jean-Paul"],
[29682886, "DEMO Martin"],
[29682887, "Johan"],
[29682892, "Peter"],
[29682900, "Antoine"],
[29682902, "Sandra"],
[29682906, "Kevin"],
[29682910, "Wouter"],
[29682911, "Tom"],
[4, "Autotask"],
];
res3 = [
[29682911, "2019-05-16T08:25:32Z"],
[29682885, "2019-07-01T13:11:00Z"],
[29682902, "2019-07-03T10:21:07Z"],
[29682885, "2019-09-03T14:00:45Z"],
[29682885, "2019-09-11T09:59:07Z"],
[29682902, "2019-09-17T14:13:39Z"],
[29682885, "2019-10-09T16:48:41Z"],
[29682885, "2019-10-30T13:48:12Z"],
[29682885, "2019-10-30T14:13:01Z"],
[29682885, "2019-10-30T14:34:13Z"],
[29682911, "2019-11-07T13:41:27Z"],
[29682911, "2019-11-22T12:41:08Z"]
]
res2.sort();
res3.sort();
const prepArray = {};
res3.forEach(sale => {
res2.forEach(person => {
if (sale[0] === person[0]) {
if (person[1] === undefined) {
person[1] = 1;
}
prepArray[person[1]] = prepArray[person[1]] || 0;
prepArray[person[1]] += 1;
}
});
});
console.log(prepArray)
I'm studying React and json objects, but I can't obtain what i want:
Here is the code:
const selectOptions1 = {
9: 'good',
14: 'Bad',
26: 'unknown'
};
const selectOptions2 = options.map((item) => {
return (
{ [item.value]:item.label }
)
})
console.log(selectOptions1) // {9:good, 14:bad, 26:unknown}
console.log(selectOptions2) // [{…}, {…}, {…}] -> 0: {9: "good"} 1: {14: "bad"} 2: {26: "unknown"}
How can I create an object like selectOptions1 using map (instead of the structure like in selectOptions2)?
you should use Reduce instead of map
const options = [
{value: 1, label : 'one'},
{value: 2, label : 'two'},
{value: 3, label : 'three'},
{value: 41, label : 'four'},
{value: 32, label : 'five'},
]
var obj = options.reduce((accumulator, current) => {
return {
[current.value]: current.label,
...accumulator,
}
}, {});
console.log(obj);
Because map transform every item into a new one and returns a list of the same length with the transformation applied. you are transforming every {value, label} object into a new {value, label} object.
reduce accumulates and returns only one result, that can be a list or something else if you have creativity with it, here i'm using the Spread operator to accumulate keys in one object.
I have a problem. I have a list of data that I output grouped. Now I want to output the values e.g. erzeugenGes to a barchart. Chart modules itself works. Fail only at the grouped data for evaluation.
Enclosed my code and list
1,2,3,4,5,6,7,8,9,10,11,12 are the Month for the ChartLabels
1.
1: [{…}]
2: [{…}]
3: [{…}]
4: [{…}]
5: [{…}]
6: [{…}]
7: [{…}]
8: [{…}]
9: Array(1)
0: {jahr: 2020, monat: 9, erzeugungGes: 901.04, verbrauchGes: 952.22, eigenverbrauch: 515.24, …}
length: 1
__proto__: Array(0)
10: Array(2)
0:
bezogen: 252.18
eigenverbrauch: 201.62
eingespeist: 140.94
erzeugungGes: 342.53
jahr: 2019
monat: 10
verbrauchGes: 453.75
__proto__: Object
1:
bezogen: 232.07
eigenverbrauch: 174.13
eingespeist: 102.37
erzeugungGes: 276.48
jahr: 2020
monat: 10
verbrauchGes: 406.19
__proto__: Object
length: 2
__proto__: Array(0)
11: Array(1)
0: {jahr: 2019, monat: 11, erzeugungGes: 291.87, verbrauchGes: 761.16, eigenverbrauch: 238.38, …}
length: 1
__proto__: Array(0)
12: [{…}]
/// and Data
getData() {
this.ds.getAuswertungJahr().subscribe(res => {
this.daten = res;
this.data = this.daten.reduce((r, a) => { console.log("a", a); console.log('r', r); r[a.monat] = [...r[a.monat] || [], a]; return r; }, {}); console.log("group", this.data);
this.barChartData[0].data = [];
for (let i = 0; i < this.data.lenght; i++) {
this.barChartData[0].data.push(this.data[i]);
}
})
}
Thanks
So, I'm a javascript n00b. Have heard that case/switch statements are...passé. I'm trying to wrap my head around object literals as their replacement structure.
After searching and trying various iterations in my code, I still cannot figure out why the "switch" variable value is coming back as "undefined". In my limited experience, a variable with a value of "undefined" usually means that it has no value, right? Is it a variable scope issue?
From what I gather the code is doing is creating a object (mod). The mod object has properties with the name of [3-18]. Each of these properties have values which are functions. These functions return a string value.
Here's what I've got so far:
function getModValue(str) {
var search = str;
var mod = {
3: function() {return "-3";},
4: function() {return "-2";},
5: function() {return "-2";},
6: function() {return "-1";},
7: function() {return "-1";},
8: function() {return "-1";},
9: function() {return "0";},
10: function() {return "0";},
11: function() {return "0";},
12: function() {return "0";},
13: function() {return "+1";},
14: function() {return "+1";},
15: function() {return "+1";},
16: function() {return "+2";},
17: function() {return "+2";},
18: function() {return "+3";}
}
mod[search]();
}
alert(getModValue("14"));
Here is my (non)working example: jsfiddle
Thanks in advance for your help.
The error is just you forgot the return at the end.
I think you are overengineering. This works and it's much more simple:
function getModValue(str) {
var mod = {
3: "-3",
5: "-2",
4: "-2",
6: "-1",
7: "-1",
8: "-1",
9: "0",
10: "0",
11: "0",
12: "0",
13: "+1",
14: "+1",
15: "+1",
16: "+2",
17: "+2",
18: "+3"
}
return mod[str];
}
alert(getModValue("14"));
PS: Checking a 3d6 roll?
UPDATE: Think that mod is a map, where the keys are numbers and the values are strings. When you look for a value using the key, Javascript has to compare your key with the existing ones. Check the following:
var number="1";
number==1 //true, because it's like if '==' makes a "toString()"
number===1 //false
var myObj={hello: function(){ return "Hello";}};
myObj.hello();
myObj["hello"](); // equivalent
const responseToParse = {
3: '-3',
4: '-2',
5: '-2',
6: '-1',
7: '-1',
8: '-1',
9: '0',
10: '0',
11: '0',
12: '0',
13: '+1',
14: '+1',
15: '+1',
16: '+2',
17: '+2',
18: '+3',
19: undefined,
20: null
}
const MyObjectLiteralLibrary = {
3: response => response[3],
4: response => response[4],
5: response => response[5],
6: response => response[6],
7: response => response[7],
8: response => response[8],
9: response => response[9],
10: response => response[10],
11: response => response[11],
12: response => response[12],
13: response => response[13],
14: response => response[14],
15: response => response[15],
16: response => response[16],
17: response => response[17],
18: response => response[18],
19: response => response[19],
20: response => response[20]
}
let str
str = 14
console.log(MyObjectLiteralLibrary[str](responseToParse))
str = 19
console.log(MyObjectLiteralLibrary[str](responseToParse))
str = 20
console.log(MyObjectLiteralLibrary[str](responseToParse))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Nice one; Yes, object literals are better than a switch when some of the cases returning an undefined or a specific cases only. This can be done through switch but will leave a fall-through in many cases.
I played around and came up with this logic in ES6 format. Please look into the code snippet above if that helps.
You can loop over defaultList of cases or a set of required cases. Also, If you want to parse a JSON object this is very helpful.
You have missed return on last line of your api.
return modsearch;