I automatically generate an array of objects in a random order. This means that the initial order of objects can be different.
var a = [{account: true},{name: true},{amount: true},{address: true}];
or
var a = [{name: true},{account: true},{amount: true},{address: true}];
How to expose objects to a given pattern?
var a = [{amount: true},{address: true},{account: true},{name: true}];
How can I arrange the automatically generated elements in a different order each time in a special order? I need the items to be in order - amount, address, account, name.
AND I have the solution!
var order = [{account: true},{name: true},{amount: true},{address: true}];
var pattern = [{amount: true},{address: true},{account: true},{name: true}];
var sort = pattern.map(pattern => order.find(order => order[0] === pattern[0]));
console.log(sort); //[{amount: true},{address: true},{account: true},{name: true}]
I'm not able to get a correct sort using your code. It seems to return an array with all the same elements of whatever is the first element of the order array.
[{ account: true },{ account: true },{ account: true },{ account: true }]
const order = [
{ account: true },
{ name: true },
{ amount: true },
{ address: true }
];
const pattern = [
{ amount: true },
{ address: true },
{ account: true },
{ name: true }
];
var sort = pattern.map((pattern) =>
order.find((order) => order[0] === pattern[0])
);
console.log("unsorted: ", JSON.stringify(order));
console.log("sorted: ", JSON.stringify(sort));
Here's a sort that does appear to sort your array element objects.
const sortedData = data.sort(
(a, b) =>
!!b.amount - !!a.amount ||
!!b.address - !!a.address ||
!!b.account - !!a.account ||
!!b.name - !!a.name
);
This works by coercing the undefined values to a boolean (i.e. undefined -> false) and then uses numerical comparison by again coercing the boolean values to type number (true -> 1, false -> 0), which results in sort comparator result values of [-1, 0, 1].
const data = [
{ account: true },
{ name: true },
{ amount: true },
{ address: true }
];
console.log("unsorted: ", JSON.stringify(data));
const sortedData = data.sort(
(a, b) =>
!!b.amount - !!a.amount ||
!!b.address - !!a.address ||
!!b.account - !!a.account ||
!!b.name - !!a.name
);
console.log("sorted: ", JSON.stringify(sortedData));
I have an array of objects that returns 3 possible sensitivity values: "LOW", "MEDIUM", "HIGH". However with the code below it is sorting in "HIGH - MEDIUM and LOW" respectively in ascending order and I wish it to return "HIGH - MEDIUM and LOW". What can I fix in this code?
In this function I compare the sensitivities received in the array
orderItemsByOrderOption = (items) => {
switch (this.state.selectedOrderOption.column) {
case "sensitivity":
return items.sort((a, b) => {
if (a.sensitivity > b.sensitivity) {
return 1;
}
if (a.sensitivity < b.sensitivity) {
return -1;
}
// a must be equal to b
return 0;
});
You could create an array with desired order and use the index of your array elements' sensitivity in this array for sorting.
Example
const arr = [
{ sensitivity: "MEDIUM" },
{ sensitivity: "LOW" },
{ sensitivity: "HIGH" }
];
const order = ["HIGH", "MEDIUM", "LOW"];
arr.sort((a, b) => order.indexOf(a.sensitivity) - order.indexOf(b.sensitivity));
console.log(arr);
There is a way is to convert rank into numeric value and compare that value
const data = [
{ id: 1, sensitivity: "LOW" },
{ id: 2, sensitivity: "HIGH" },
{ id: 3, sensitivity: "LOW" },
{ id: 4, sensitivity: "MEDIUM" },
{ id: 5, sensitivity: "HIGH" },
{ id: 6, sensitivity: "MEDIUM" },
];
const getRankInNum = (el) =>
({
HIGH: 2,
MEDIUM: 1,
LOW: 0,
}[el.sensitivity] || -1);
const res = data.sort((a, b) => getRankInNum(b) - getRankInNum(a));
console.log(res);
You could create a sort order lookup that maps HIGH, MEDIUM, and LOW to numeric values since sorting them alphabetically doesn't make sense.
const sensitivitySortOrder = {
HIGH: 0,
MEDIUM: 1,
LOW: 2
};
orderItemsByOrderOption = (items) => {
switch (this.state.selectedOrderOption.column) {
case "sensitivity":
return items.sort((a, b) => {
const aRank = sensitivitySortOrder[a.sensitivity];
const bRank = sensitivitySortOrder[b.sensitivity];
if (aRank > bRank) {
return 1;
}
if (aRank < bRank) {
return -1;
}
// a must be equal to b
return 0;
});
I have this Array with 6 different dates from db:
[{"_id":{"source":"2019-04-06","status":false},"count":1},
{"_id":{"source":"2019-04-06","status":true},"count":1},
{"_id":{"source":"2019-03-24","status":false},"count":2},
{"_id":{"source":"2019-03-24","status":true},"count":1},
{"_id":{"source":"2019-03-23","status":false},"count":3},
{"_id":{"source":"2019-03-08","status":false},"count":1},
{"_id":{"source":"2019-02-02","status":true},"count":1},
{"_id":{"source":"2019-02-02","status":false},"count":2},
{"_id":{"source":"2019-01-29","status":false},"count":1}]
What i need are 2 Arrays with the length of 6 items and the value of "count"
If only status "true" exists for a date, then i need to push a count: "0" to the false-array.
And if only status "false" exists for a date, then i need to push a count: "0" to the true-array.
It should look like this:
Arrayforstatusfalse = [1,2,3,1,2,1]
Arrayforstatustrue = [1,1,0,0,1,0]
But what i get is this:
Arrayforstatusfalse = [1,2,3,1,2,1]
Arrayforstatustrue = [1,1,1]
Update:
Sorry for this ugly code. i will be more precise. And thanks for your help.
this.responsedata = input
this.line1 = output for all the "false"
this.line2 = output for all the "true"
I loop over input data with condition and push it into the new arrays:
for (var i=0; i<this.responsedata.length;i++) {
if (this.responsedata[i]._id.status === true ) {
console.log('true exits for date: ' + JSON.stringify(this.responsedata[i]._id.source) + JSON.stringify(this.responsedata[i].count) )
this.line2.push(this.responsedata[i])
}
if (this.responsedata[i]._id.status === false ) {
console.log('false exits for date: ' + JSON.stringify(this.responsedata[i]._id.source) + JSON.stringify(this.responsedata[i].count) )
this.line1.push(this.responsedata[i])
}
}
Console :
[Log] false exits for date: "2019-04-06"1
[Log] true exits for date: "2019-04-06"1
[Log] false exits for date: "2019-03-24"2
[Log] true exits for date: "2019-03-24"1
[Log] false exits for date: "2019-03-23"3
[Log] false exits for date: "2019-03-08"1
[Log] true exits for date: "2019-02-02"1
[Log] false exits for date: "2019-02-02"2
[Log] false exits for date: "2019-01-29"1
[Log] line1[1,2,3,1,2,1]
[Log] line2[1,1,1]
And here i need line2 = [1,1,0,0,1,0]
because i need a 0 "if not exits on this date"..
You could take a Map for keeping the same index in insertation order of the given data.
var array = [{ _id: { source: "2019-04-06", status: false }, count: 1 }, { _id: { source: "2019-04-06", status: true }, count: 1 }, { _id: { source: "2019-03-24", status: false }, count: 2 }, { _id: { source: "2019-03-24", status: true }, count: 1 }, { _id: { source: "2019-03-23", status: false }, count: 3 }, { _id: { source: "2019-03-08", status: false }, count: 1 }, { _id: { source: "2019-02-02", status: true }, count: 1 }, { _id: { source: "2019-02-02", status: false }, count: 2 }, { _id: { source: "2019-01-29", status: false }, count: 1 }],
result = array.reduce((m => (r, { _id: { source, status }, count }) => {
var index = m.get(source);
if (index === undefined) {
m.set(source, index = m.size);
r.true[index] = 0;
r.false[index] = 0;
}
r[status][index] = count;
return r;
})(new Map), { true: [], false: [] }),
{ true: trues, false: falses } = result;
console.log(...trues);
console.log(...falses);
You can use reduce() to summarize the array into an object using the source as key. Convert the object into array using Object.entries and reduce it again to convert the inner child object into an array.
Use destructuring assignment syntax to assign into variables.
let array = [{"_id":{"source":"2019-04-06","status":false},"count":1},{"_id":{"source":"2019-04-06","status":true},"count":1},{"_id":{"source":"2019-03-24","status":false},"count":2},{"_id":{"source":"2019-03-24","status":true},"count":1},{"_id":{"source":"2019-03-23","status":false},"count":3},{"_id":{"source":"2019-03-08","status":false},"count":1},{"_id":{"source":"2019-02-02","status":true},"count":1},{"_id":{"source":"2019-02-02","status":false},"count":2},{"_id":{"source":"2019-01-29","status":false},"count":1}];
let {Arrayforstatusfalse,Arrayforstatustrue} = Object.entries(array.reduce((c, v) => {
c.Arrayforstatustrue[v._id.source] = c.Arrayforstatustrue[v._id.source] || 0;
c.Arrayforstatusfalse[v._id.source] = c.Arrayforstatusfalse[v._id.source] || 0;
if (v._id.status) c.Arrayforstatustrue[v._id.source] += v.count;
else c.Arrayforstatusfalse[v._id.source] += v.count;
return c;
}, {Arrayforstatusfalse: {},Arrayforstatustrue: {}}))
.reduce((c, [k, o]) => Object.assign(c, {[k]: Object.values(o)}), {});
console.log(Arrayforstatusfalse);
console.log(Arrayforstatustrue);
This?
const data = [
{"_id":{"source":"2019-04-06","status":false},"count":1},
{"_id":{"source":"2019-04-06","status":true},"count":1},
{"_id":{"source":"2019-03-24","status":false},"count":2},
{"_id":{"source":"2019-03-24","status":true},"count":1},
{"_id":{"source":"2019-03-23","status":false},"count":3},
{"_id":{"source":"2019-03-08","status":false},"count":1},
{"_id":{"source":"2019-02-02","status":true},"count":1},
{"_id":{"source":"2019-02-02","status":false},"count":2},
{"_id":{"source":"2019-01-29","status":false},"count":1},
];
const byDate = {};
data.forEach((f, ndx) => {
byDate[f._id.source] = byDate[f._id.source] || [];
byDate[f._id.source].push(f);
});
function mapCounts(byDate, status) {
return Object.values(byDate).map(d => {
const ndx = d.findIndex(e => e._id.status === status);
return ndx >= 0 ? d[ndx].count : 0;
});
}
const falseForDate = mapCounts(byDate, false);
const trueForDate = mapCounts(byDate, true);
console.log(falseForDate.join(','));
console.log(trueForDate.join(','));
note I'm curious what this is acutally for. The code above will not handle things if there are 3 of the same date because then there are would either be 2 counts for true or 2 for false. Which count to use. Similarly the same sitatuion arrises if their are 2 trues or 2 falses for the same date (same issue really). Maybe you want to sum the counts for true or false by date?
In that case
const data = [
{"_id":{"source":"2019-04-06","status":false},"count":1},
{"_id":{"source":"2019-04-06","status":true},"count":1},
{"_id":{"source":"2019-03-24","status":false},"count":2},
{"_id":{"source":"2019-03-24","status":true},"count":1},
{"_id":{"source":"2019-03-23","status":false},"count":3},
{"_id":{"source":"2019-03-08","status":false},"count":1},
{"_id":{"source":"2019-02-02","status":true},"count":1},
{"_id":{"source":"2019-02-02","status":false},"count":2},
{"_id":{"source":"2019-01-29","status":false},"count":1},
];
const byDate = {};
data.forEach((f, ndx) => {
byDate[f._id.source] = byDate[f._id.source] || [];
byDate[f._id.source].push(f);
});
function mapCounts(byDate, status) {
return Object.values(byDate).map(d => {
return d.reduce((acc, e) => acc + (e._id.status === status ? e.count : 0), 0);
});
}
const falseForDate = mapCounts(byDate, false);
const trueForDate = mapCounts(byDate, true);
console.log(falseForDate.join(','));
console.log(trueForDate.join(','));
or
const data = [
{"_id":{"source":"2019-04-06","status":false},"count":1},
{"_id":{"source":"2019-04-06","status":true},"count":1},
{"_id":{"source":"2019-03-24","status":false},"count":2},
{"_id":{"source":"2019-03-24","status":true},"count":1},
{"_id":{"source":"2019-03-23","status":false},"count":3},
{"_id":{"source":"2019-03-08","status":false},"count":1},
{"_id":{"source":"2019-02-02","status":true},"count":1},
{"_id":{"source":"2019-02-02","status":false},"count":2},
{"_id":{"source":"2019-01-29","status":false},"count":1},
];
const byDate = {};
data.forEach((f, ndx) => {
byDate[f._id.source] = byDate[f._id.source] || [0, 0];
byDate[f._id.source][f._id.status === true ? 1 : 0] += f.count;
});
const falseForDate = Object.values(byDate).map(v => v[0]);
const trueForDate = Object.values(byDate).map(v => v[1]);
console.log(falseForDate.join(','));
console.log(trueForDate.join(','));
You can use map to achieve this. They key of the map will be the source and value will be count. If no value found for a particular key, then assign 0. Otherwise assign value based on the given condition.
Iterate over all elements of inputArray. After the end of iteration, you will get two objects. Just take the values of the objects using Object.values() function.
You're done!!!
I have used ternary operator to make the code look short and easy. See the snippet below
var inputArray = [{"_id":{"source":"2019-04-06","status":false},"count":1},{"_id":{"source":"2019-04-06","status":true},"count":1},{"_id":{"source":"2019-03-24","status":false},"count":2},{"_id":{"source":"2019-03-24","status":true},"count":1},{"_id":{"source":"2019-03-23","status":false},"count":3},{"_id":{"source":"2019-03-08","status":false},"count":1},{"_id":{"source":"2019-02-02","status":true},"count":1},{"_id":{"source":"2019-02-02","status":false},"count":2},{"_id":{"source":"2019-01-29","status":false},"count":1}];
var trueObjects = {},
falseObjects = {};
inputArray.forEach(function(elem) {
var index = elem._id.source,
status = elem._id.status,
count = elem.count;
//initialize value for new index
trueObjects[index] = trueObjects[index] ? trueObjects[index] : 0;
falseObjects[index] = falseObjects[index] ? falseObjects[index] : 0;
//set value based on condition
trueObjects[index] = status ? count : trueObjects[index];
falseObjects[index] = !status ? count : falseObjects[index];
});
trueArray = Object.values(trueObjects);
falseArray = Object.values(falseObjects);
console.log(falseArray);
console.log(trueArray);
You can get unique sources (dates) and create true and false arrays for each source :
const dataArray = [{"_id":{"source":"2019-04-06","status":false},"count":1},
{"_id":{"source":"2019-04-06","status":true},"count":1},
{"_id":{"source":"2019-03-24","status":false},"count":2},
{"_id":{"source":"2019-03-24","status":true},"count":1},
{"_id":{"source":"2019-03-23","status":false},"count":3},
{"_id":{"source":"2019-03-08","status":false},"count":1},
{"_id":{"source":"2019-02-02","status":true},"count":1},
{"_id":{"source":"2019-02-02","status":false},"count":2},
{"_id":{"source":"2019-01-29","status":false},"count":1}];
// Get all sources
const sources = dataArray.map(item => item._id.source);
// Get unique sources
const uniqueSources = [...(new Set(sources))];
const arrayForStatusTrue = [];
const arrayForStatusFalse = [];
uniqueSources.forEach(source => {
// Check if source with status true exists
const itemWithStatusTrue = dataArray.find(item => (item._id.status && item._id.source === source));
itemWithStatusTrue ? arrayForStatusTrue.push(itemWithStatusTrue.count) : arrayForStatusTrue.push(0);
// Check if source with status false exists
const itemWithStatusFalse = dataArray.find(item => (!item._id.status && item._id.source === source));
itemWithStatusFalse ? arrayForStatusFalse.push(itemWithStatusFalse.count) : arrayForStatusFalse.push(0);
});
console.log(arrayForStatusTrue);
console.log(arrayForStatusFalse);
I would suggest using a Map to create one entry per date (source), which each would have two values representing the counts for both possible statuses (initialised with zero).
Then add the actual counts to those entries, and finally extract the data into the two arrays you expect:
// Sample input
const array = [{ _id: { source: "2019-04-06", status: false }, count: 1 }, { _id: { source: "2019-04-06", status: true }, count: 1 }, { _id: { source: "2019-03-24", status: false }, count: 2 }, { _id: { source: "2019-03-24", status: true }, count: 1 }, { _id: { source: "2019-03-23", status: false }, count: 3 }, { _id: { source: "2019-03-08", status: false }, count: 1 }, { _id: { source: "2019-02-02", status: true }, count: 1 }, { _id: { source: "2019-02-02", status: false }, count: 2 }, { _id: { source: "2019-01-29", status: false }, count: 1 }];
// Algorithm
const map = new Map(array.map(o => [o._id.source, [0,0]]));
array.forEach(o => map.get(o._id.source)[+o._id.status] += o.count);
const [noes, ayes] = [0, 1].map(i => Array.from(map.values(), a => a[i]));
// Output
console.log(JSON.stringify(noes), JSON.stringify(ayes));
const confirmations = {
quantity: false,
total_price: true,
unit_price: true
}
// Should print -> Total Price & Unit Price
// If three variables are true then should print -> Quantity, Total Price & Unit Price
I know this can be achieved using couple of if...else statements but that's really lame. Is there other way to achieve this?
You could take another object for wording and then create a nice string by replacing the last two words with an ampersand and all words before join with comma.
function getString(confirmations) {
const
nice = a => a.concat(a.splice(-2, 2).join(' & ')).join(', '),
words = { quantity: 'Quantity', total_price: 'Total Price', unit_price: 'Unit Price' };
return nice(Object
.entries(confirmations)
.filter(([, v]) => v)
.map(([w]) => words[w])
);
}
console.log(getString({ quantity: false, total_price: true, unit_price: true }));
console.log(getString({ quantity: true, total_price: true, unit_price: true }));
console.log(getString({ quantity: false, total_price: true, unit_price: false }));
You can do:
const confirmations1 = {quantity: false, total_price: true, unit_price: true};
const confirmations2 = {quantity: true, total_price: true, unit_price: true};
const getFormattedSentence = obj => Object
.keys(obj)
.filter(k => obj[k])
.map(k => k
.split('_')
.map(w => w.charAt(0).toUpperCase() + w.slice(1))
.join(' ')
)
.join(', ')
.replace(/,(?!.*,)/gmi, ' &');
console.log(getFormattedSentence(confirmations1));
console.log(getFormattedSentence(confirmations2));
Here is my attempt. Much slimmer after studying Yosvel Quintero's version
const fmtText = obj => Object
.keys(obj) // array of keys
.filter(k => obj[k]) // take only the true ones
.join(", ") // join found keys with ,
.replace(/_/g, " ") // replace the underscore
.replace(/\b([a-z])/g, x => x.toUpperCase()) // InitialCap
.replace(/,(?=[^,]*$)/, ' &'); // replace last comma
const conf1 = { quantity: false, total_price: true, unit_price: true }
const conf2 = { quantity: true, total_price: true, unit_price: true }
const conf3 = { quantity: false, total_price: true, unit_price: false }
console.log(fmtText(conf1))
console.log(fmtText(conf2))
console.log(fmtText(conf3))
This should do the job :
const confirmations = {
quantity: false,
total_price: true,
unit_price: true
};
// filter out false values and return object keys as an array of strings
const validatedConfirmations = Object.keys(confirmations).filter((name) => confirmations[name]);
// make them human readable
const humanReadableConfirmations = validatedConfirmations.map(makeItHumanReadable);
// crunch it all to a single string
const lastConfirmationMessage = humanReadableConfirmations.pop();
const confirmationMessage = humanReadableConfirmation.join(', ') + ` & ${lastConfirmationMessage}`;
Careful, if only one element is true, it will display "& Unit Price", you can adapt it anyway.