I am here want to use map function in javascript to loop a type data array,but i get error for these syntax below :
function porti(scores) {
const test = scores.map(pass, fail) => {
if (scores < 75){
test.fail
} else {
test.pass
}
return {pass, fail}
}
}
output must be, if scores < 75 : fail, else : pass
console.log(porti([80, 45, 90, 65, 74, 100, 85, 30]));
// { pass: [ 80, 90, 100, 85 ], fail: [ 45, 65, 74, 30 ] }
console.log(porti([]));
// { pass: [], fail: [] }
I think reduce would be better for this situation. This will allow us to reduce the array to an object of two item arrays.
let items = [80, 45, 90, 65, 74, 100, 85, 30]
let result = items.reduce((obj, item) => {
item < 75 ? obj.fail.push(item) : obj.pass.push(item)
return obj
}, {pass:[], fail:[]})
console.log(result)
If you wanted to use filter you could...
let items = [80, 45, 90, 65, 74, 100, 85, 30]
let result = {
pass: items.filter(i => i >= 75),
fail: items.filter(i => i < 75)
}
console.log(result)
And here is how we can do it with forEach...
let items = [80, 45, 90, 65, 74, 100, 85, 30]
let result = {pass:[], fail:[]}
items.forEach(itm => itm < 75 ? result.fail.push(itm) : result.pass.push(itm))
console.log(result)
You could integrate the check as ternary for getting the key for pushing.
function porti(scores) {
var result = { pass: [], fail: [] },
score;
for (score of scores) {
result[score < 75 ? 'fail': 'pass'].push(score);
}
return result
}
console.log(porti([80, 45, 90, 65, 74, 100, 85, 30]));
console.log(porti([]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
As mentioned above .map() should best be saved for when you are looking to return an array by manipulating a previous array. If you don't wish to use a vanilla for loop. You could try this
const testScores = [...someArray of numbers]
function porti(tesScores) {
const result = {
pass: [],
fail: []
}
for (let score of testScores) {
if (score < 75) {
result.fail.push(score)
} else {
result.pass.push(score)
}
return result
}}
Related
The second function will take the array as a parameter
How would you send the inner function as a parameter?
const score = [98, 76, 94, 82, 70, 95, 45, 90]
const determinePass = function (threshold) {
return function (array) {
return array.map(function (value) {
return value > threshold ? "pass" : "fail";
})
}
}
this is how you call the return function.
determinePass(threshold)(array);
// for example
// determinePass(50)(score)
const score = [98, 76, 94, 82, 70, 95, 45, 90]
const determinePass = function (threshold) {
return function (array) {
return array.map(function (value) {
return value > threshold ? "pass" : "fail";
})
}
}
console.log(determinePass(50)(score));
This returns an array of pass or fail. The parameter is in the determinePass function.
const score = [98, 76, 94, 82, 70, 95, 45, 90]
function determinePass(threshold, array){
return array.map(function (value) {
return value > threshold ? "pass" : "fail";
});
}
console.log(determinePass(50, score));
Or
const score = [98, 76, 94, 82, 70, 95, 45, 90]
function determinePass(threshold){
return score.map(function (value) {
return value > threshold ? "pass" : "fail";
});
}
console.log(determinePass(50));
I'm looking for the fastest way to merge multiple pre-sorted arrays, into one sorted array, without duplicates.
For example:
const arrays = [
[15, 30, 35, 40, 45, 50],
[33, 36, 39, 42, 45, 48],
[37, 38, 39, 40, 41, 42]
];
Should output:
[15, 30, 33, 35, 36, 37, 38, 39, 40, 41, 42, 45, 48, 50]
In reality these arrays are much larger so I'm looking for a fast way to do this.
This question is about performance I'm aware it can be done in with concat and sort in O(n log(n)) but I'm looking for something O(n).
Untested. I don't think my code is optimal, but I currently don't see a better way to approach this.
Further small improvements might be:
using ordinary for loops instead of Array.prototype.reduce
removing arrays that reach a "done" status (instead of just flagging them as done)
console.time("Creation of arrays");
const arrays = Array.from({ length: 1000 }, (_, row) => {
return Array.from({ length: 100000 }, (_, i) => row + i);
});
console.timeEnd("Creation of arrays");
const createMergedArray = (arrays) => {
console.time("Creation of toProcess");
const toProcess = arrays.map((array, row) => {
return { done: false, row, column: 0, array };
});
console.timeEnd("Creation of toProcess");
const merged = [];
while (toProcess.some(({ done }) => !done)) {
const scan = toProcess.reduce(
(acc, item) => {
if (!item.done) {
if (item.array[item.column] < acc.minimum) {
acc.minimum = item.array[item.column];
acc.rows = [item.row];
} else if (item.array[item.column] === acc.minimum) {
acc.rows.push(item.row);
}
}
return acc;
},
{ rows: [], minimum: Infinity }
);
merged.push(scan.minimum);
scan.rows.forEach((row) => {
const item = toProcess[row];
while (item.array[item.column] === scan.minimum) {
++item.column;
}
item.done = item.array.length === item.column;
});
}
return merged;
};
console.time("Merging");
const merged = createMergedArray(arrays);
console.timeEnd("Merging");
console.assert(
merged.every((n, i, arr) => n > arr[i - 1] || 0 === i),
"Unsorted or duplicates found"
);
You didn't mention the size of your arrays, so I used 1k rows with 100k columns.
If you pass your arrays (number[][]) to createMergedArray, it should give you:
an array of unique numbers sorted ascendingly
an idea of whether this approach is viable for the size of your data
I want to compare values from objects that I keep in an array.
I know that I can create new arrays with values from each object but I'm trying to find some way to do it without creating them.
Consider we have such situation:
soldiers[first, second, third]
first{name: John, shooting: 95, combat: 50, tactic: 88}
second{name: Arnold, shooting: 97, combat: 72, tactic: 68}
third{name: William, shooting: 87, combat: 86, tactic: 97}
I'd like to select the best soldier from the provided above - but I can't create one rating (i.e. average).
There will be some conditions that soldier must fill - for example: at least 60 points in combat (no matter if every other property is 100).
So I'm trying to find way to compare multiple properties and return name of just one soldier.
I'll appreciate every tip. Thanks!
I have made you an exmaple with comments. Let me know if this pushes you in the right direction or if you need any other help.
const soldiers = [{
name: "John",
shooting: 95,
combat: 50,
tactic: 88
},
{
name: "Arnold",
shooting: 97,
combat: 72,
tactic: 68
},
{
name: "William",
shooting: 87,
combat: 86,
tactic: 97
}
];
const filteredSoldiers = soldiers
.filter(soldier => soldier.combat > 60) // Find every soldier where combat is higher than 60
.map(soldier => {
return {
name: soldier.name,
average: (soldier.combat + soldier.tactic + soldier.shooting) / 3
};
// map will return an array with the filtered soldiers, and we put their average and their name in there
})
.sort((a, b) => b.average - a.average);
// Lastly we sort them high to low by their average score
console.log(
filteredSoldiers.length > 0 ? filteredSoldiers[0].name : 'No soldiers with combat score higher thn 60'
);
jsfiddle
In the filter condition you can of course add more checks.
You need to got through all items and select best value;
Note that some soldiers can have similar values, that's why values.name is array
let a = {
name: "John", shooting: 95, combat: 50, tactic: 88
};
let b = {
name: "Arnold", shooting: 97, combat: 72, tactic: 68
};
let c = {
name: "William", shooting: 87, combat: 86, tactic: 97
};
let soldiers = [a, b, c];
let values = {
shooting: {
name: [],
score: 0
},
combat: {
name: [],
score: 0
},
tactic: {
name: [],
score: 0
}
};
soldiers.map((item) => {
['shooting', 'combat', 'tactic'].forEach(name => {
if (item[name] > values[name].score) {
values[name].name = [item.name];
values[name].score = item[name];
} else if (item[name] === values[name].score) {
values[name].name.push(item.name);
}
});
});
console.log(values);
I have some data passed in via a query string and I've converted it to an object like:
{
"Person1_Age": 22,
"Person1_Height": 170,
"Person1_Weight": 72,
"Person2_Age": 27,
"Person2_Height": 160,
"Person2_Weight": 56,
}
I want to convert this to an array of objects like this:
[
{
"name": "Person1",
"age": "22",
"height": 170,
"weight": 72
},
{
"name": "Person2",
"age": "27",
"height": 160,
"weight": 56
}
]
What would be the best way to do this? Thanks!
You could do this with forEach loop and optional thisArg parameter
var data = {
"Person1_Age": 22,
"Person1_Height": 170,
"Person1_Weight": 72,
"Person2_Age": 27,
"Person2_Height": 160,
"Person2_Weight": 56,
}
var result = [];
Object.keys(data).forEach(function(e) {
var part = e.split('_');
var person = part[0];
var p = part[1].toLowerCase();
if(!this[person]) {
this[person] = {name: person}
result.push(this[person]);
}
this[person][p] = data[e];
}, {})
console.log(result);
Here's one way to do it
var obj = {
"Person1_Age": 22,
"Person1_Height": 170,
"Person1_Weight": 72,
"Person2_Age": 27,
"Person2_Height": 160,
"Person2_Weight": 56,
}
var map = {}, arr = [];
Object.keys(obj).forEach(function(k) {
var parts = k.split('_'),
key = parts.shift().toLowerCase(),
val = parts.pop().toLowerCase();
if (!(key in map)) map[key] = {};
map[key][val] = obj[k];
});
for (var k in map) {
map[k].name = k;
arr.push(map[k]);
}
document.body.innerHTML = '<pre>' + JSON.stringify(arr, 0, 4) + '</pre>';
You could use a hash table for reference and push the object to the Array, if a new hash is found.
var obj = { Person1_Age: 22, Person1_Height: 170, Person1_Weight: 72, Person2_Age: 27, Person2_Height: 160, Person2_Weight: 56 },
arr = [];
Object.keys(obj).forEach(function(k) {
var parts = k.split('_');
if (!this[parts[0]]) {
this[parts[0]] = { name: parts[0] };
arr.push(this[parts[0]]);
}
this[parts[0]][parts[1].toLowerCase()] = obj[k];
}, Object.create(null));
console.log(arr);
Just for the record, this can also be done directly as the result of a .reduce() method.
var list = {
"Person1_Age": 22,
"Person1_Height": 170,
"Person1_Weight": 72,
"Person2_Age": 27,
"Person2_Height": 160,
"Person2_Weight": 56
};
var res = Object.keys(list).reduce(function(a, b) {
var m = b.match(/Person(\d+)_(.+)/);
(a[m[1] - 1] = a[m[1] - 1] || {name: 'Person' + m[1]})[m[2].toLowerCase()] = list[b];
return a;
}, []);
console.log(res);
Below is the layout of my JSON File.
{
"questions": ["Question1", "Question2"],
"orgs": ["Org1", "Org2", "Org3"],
"dates": ["Q1", "Q2", "Q3"],
"values": [
[
[5, 88, 18],
[50, 83, 10],
[29, 78, 80]
],
[
[46, 51, 61],
[95, 21, 15],
[49, 86, 43]
]
]
}
I'm trying to retrieve a single array of values by looping through each question, indexed by an "orgs" value and then adding each value retrieved and dividing it by data.dates.length.
Here is my code;
d3.json("data.json", function(error, data) {
var array = new Array()
var orgS = "Org2"
var org = data.orgs.indexOf(orgS);
for (var question = 0; question < data.questions.length; question++) {
array.push(
data.values[question][org]
)
console.log(array)
}
// add array together
array.reduce(function(a, b) {
return a + b;
})
// calculate average
var avg = array / data.dates.length;
})
Here is a plnk;
http://plnkr.co/edit/wMv8GmkD1ynjo9WZVlMb?p=preview
I think the issue here is how I'm retrieving the values in the first place? as at the moment, although I am retrieving the correct values in the console log, I'm getting the array twice, and both times inside nested arrays. I'm not so sure how to remedy the problem?
For reference;
[question1][org1] corresponds to the values [5, 88, 18].
Hope someone can offer some advice here?
Thanks!
Since you clarified your question to indicate you want to calculate separate averages for each question, I've rewritten my answer. You should do all the calculations in the for loop, since the loop is looping through the questions. Then store your averages in an array.
d3.json("data.json", function(error, data) {
var averages = new Array()
var orgS = "Org2"
var org = data.orgs.indexOf(orgS);
var values, sum;
for (var question = 0; question < data.questions.length; question++) {
// get the values for the question/org
values = data.values[question][org];
// calculate the sum
sum = values.reduce(function(a, b) {
return a + b;
});
// calculate the average
averages.push(sum / values.length);
}
console.log(averages);
});
Perform the .reduce() in the for loop and push that result into array. That will give you the an array of the results you expected.
array.push(data.values[question][org].reduce(function(a, b) {
return a + b
}, 0) / data.dates.length)
[
47.666666666666664,
43.666666666666664
]
Currently, you're attempting to perform addition on the arrays themselves in the .reduce() callback instead of reducing the members of each individual array to their sum, and then average.
Demo: (Click the text below to show the whole function)
var data = {
"questions": ["Question1", "Question2"],
"orgs": ["Org1", "Org2", "Org3"],
"dates": ["Q1", "Q2", "Q3"],
"values": [
[
[5, 88, 18],
[50, 83, 10],
[29, 78, 80]
],
[
[46, 51, 61],
[95, 21, 15],
[49, 86, 43]
]
]
}
x(data)
// Your callback function.
function x(data) {
var array = new Array()
var orgS = "Org2"
var org = data.orgs.indexOf(orgS);
for (var question = 0; question < data.questions.length; question++) {
array.push(data.values[question][org].reduce(function(a, b) {
return a + b
}, 0) / data.dates.length)
}
console.log(array)
}
Instead of a for loop, you could also use .map().
var array = data.questions.map(function(_, question) {
return data.values[question][org].reduce(function(a, b) {
return a + b
}, 0) / data.dates.length
})
Demo: (Click the text below to show the whole function)
var data = {
"questions": ["Question1", "Question2"],
"orgs": ["Org1", "Org2", "Org3"],
"dates": ["Q1", "Q2", "Q3"],
"values": [
[
[5, 88, 18],
[50, 83, 10],
[29, 78, 80]
],
[
[46, 51, 61],
[95, 21, 15],
[49, 86, 43]
]
]
}
x(data)
// Your callback function.
function x(data) {
var orgS = "Org2"
var org = data.orgs.indexOf(orgS);
var array = data.questions.map(function(_, question) {
return data.values[question][org].reduce(function(a, b) {
return a + b
}, 0) / data.dates.length
})
console.log(array)
}
You need to store the sum, the result of reduce.
// add array together
// store in sum
var sum = array.reduce(function(a, b) {
return a + b;
}, 0); // use 0 as start value
For the average, you do not need the length of data.dates but from array, because you collecting the values and this length is important.
// calculate average
var avg = sum / array.length;
Together for all values, you might get this
var data = { "questions": ["Question1", "Question2"], "orgs": ["Org1", "Org2", "Org3"], "dates": ["Q1", "Q2", "Q3"], "values": [[[5, 88, 18], [50, 83, 10], [29, 78, 80]], [[46, 51, 61], [95, 21, 15], [49, 86, 43]]] },
sum = [];
data.values.forEach(function (a, i) {
sum[i] = sum[i] || [];
a.forEach(function (b) {
b.forEach(function (c, j) {
sum[i][j] = sum[i][j] || 0;
sum[i][j] += c;
});
});
});
data.avg = sum.map(function (a, i) {
return a.map(function (b) {
return b / data.values[i].length;
});
});
console.log(sum);
console.log(data);