Related
Here is the item1 data:
const item1 = [
{
"proposedWaterClosets": 2,
"proposedToilets": 3,
"noOfWaterClosets": 3,
"noOfToilets": 3
},
{
"proposedWaterClosets": 2,
"proposedToilets": 3,
"noOfWaterClosets": 4,
"noOfToilets": 2
}
]
Here is the item2 data: **OPTIONAL
**
const item2 = {
"proposedWaterClosets": 2,
"proposedToilets": 3,
"noOfWaterClosets": 3,
"noOfToilets": 3
}
I want the output to be like this which only return the difference value
expected output:
[{
"noOfToilets": 2,
"noOfWaterClosets":4
}]
Here I am having issue , I am getting which the value is same .. here is my approach using map and with the help of if condition, the thing is I am getting the output which is equal ... Any suggestions would be appreciated
const result = item1.map((it) => {
if (it.noOfToilets !== item2.noOfToilets || it.noOfWaterClosets !== item2.noOfWaterClosets) {
return { oldToilets: it.noOfToilets, oldWaterC: it.noOfWaterClosets };
}
});
getting output: [{oldToilets::2,oldWaterC:3}]
UPDATE: ** Compare the array of objects can work also
If the object will remain a simple k-v mapping and not include nested objects, you can make a simple check like this:
function difference(a, b) {
const diff = {};
const allKeys = [];
// collect all the keys and make sure there are no duplicates
for (const key of [...Object.keys(a), ...Object.keys(b)]) {
if (!allKeys.includes(key)) {
allKeys.push(key);
}
}
for (const key of allKeys) {
// if this key-value is the same, ignore
if (a[key] === b[key]) {
continue;
}
// save only the difference
diff[key] = b[key];
}
return diff;
}
const item1 = {
"proposedWaterClosets": 2,
"proposedToilets": 3,
"noOfWaterClosets": 3,
"noOfToilets": 3
}
const item2 = {
"proposedWaterClosets": 2,
"proposedToilets": 3,
"noOfWaterClosets": 3,
"noOfToilets": 2
}
console.log(difference(item1, item2))
Note that in your example, item1 is an array of objects, and item2 is one object... They aren't normally comparable (they will always return difference).
If you iterate over the objects in the array and can compare between them, this will work for you.
You can simply achieve it via creating a custom compare function.
Demo :
const item1 = [
{
"proposedWaterClosets": 2,
"proposedToilets": 3,
"noOfWaterClosets": 3,
"noOfToilets": 3
},
{
"proposedWaterClosets": 2,
"proposedToilets": 3,
"noOfWaterClosets": 3,
"noOfToilets": 2
}
];
const item2 = {
"proposedWaterClosets": 2,
"proposedToilets": 3,
"noOfWaterClosets": 3,
"noOfToilets": 3
}
function compare(arr, obj) {
const res = {};
arr.forEach((item1Obj) => {
Object.keys(obj).forEach(item2 => {
if (obj[item2] !== item1Obj[item2]) {
res[item2] = item1Obj[item2];
}
});
});
return res;
}
console.log(compare(item1, item2));
You could get the entries from the object and mapp the objects with difference.
const
array = [{ proposedWaterClosets: 2, proposedToilets: 3, noOfWaterClosets: 3, noOfToilets: 3 }, { proposedWaterClosets: 2, proposedToilets: 3, noOfWaterClosets: 4, noOfToilets: 2 }],
object = { proposedWaterClosets: 2, proposedToilets: 3, noOfWaterClosets: 3, noOfToilets: 3 },
entries = Object.entries(object),
result = array.flatMap(o => {
const pairs = Object
.entries(o)
.filter(([k, v]) => object[k] !== v);
return pairs.length
? Object.fromEntries(pairs)
: []
});
console.log(result);
I have got a function that produces an array that is made up of X amount of sub-arrays containing Y amount of objects. Both of these factors are passed to a function to produce an array that looks something like this:
[
[ { '0': 3 }, { '1': 4 }, { '2': 6 }, 'Estimate:': '0jvyt8a' ],
[ { '0': 4 }, { '1': 6 }, { '2': 3 }, 'Estimate:': 'mc973fs' ],
[ { '0': 4 }, { '1': 1 }, { '2': 3 }, 'Estimate:': 'vwsfh8k' ],
[ { '0': 4 }, { '1': 3 }, { '2': 5 }, 'Estimate:': 'n6xzge3' ],
[ { '0': 8 }, { '1': 7 }, { '2': 1 }, 'Estimate:': 'v0jn7bh' ]
]
My question is, is there a way I can convert this array from this structure. To a structure shown below:
[
[1,{1: "vwsfh8k"}, {2: "v0jn7bh"}]
[3,{1: "0jvyt8a"}, {2: "mc973fs"}, {3:"vwsfh8k"}, {4:"n6xzge3"}]
]
Basically, my aim is to take the original array generated by the script (see below) and pass it through another function to record how many times each number was present and what it's 'estimate' number was.
In this example, I just created random numbers between 0 and 10 so an option would be to iterate and count each value I guess but unfortunately, I can't do this because eventually I will be using 5-letter combinations instead of numbers but numbers were easiest to show for an example and proof of concept.
So, I guess, I need to get an array of each unique value and then look at each value up in the original array to find out what estimate IDs have it present. Unfortunately, I don't have even an idea of where, to begin with, this, so I was hoping you guys can help.
Code to generate random array:
// Making an empty array
const arr = [];
//Generating the estimate IDs and placing them all in their own object in their own array.
function estimateGen(length, nodes) {
for (var i = 0; i < length; i++) {
const estimate = [];
let estimateVal = Math.random().toString(36).replace('0.','').slice(0,7);
estimate[`Estimate:`] = estimateVal;
arr.push(estimate);
nodeGen(estimate, nodes)
}
}
// Adding x amount of nodes between 1 and 10 into each estimate sub-array in their own objects.
function nodeGen(estimate, nodes) {
for (var i = 0; i < nodes; i++) {
const node = {};
let nodeID = Math.floor(Math.random() * 10) + 1;
node[i] = nodeID;
estimate.push(node);
}
}
// Calling the function and saying how many nodes per estimate we want.
estimateGen(5, 3);
console.log(arr);
If you have any suggestions on how to improve this code or as to why the estimate values in the sub-array are always last in the array that would be very helpful.
Thank you
--- EDIT ---
I have changed the code that generates the original array to produce a simpler array.
// Making an empty array
const arr = [];
//Generating the estimate IDs and placing them all in their own object in their own array.
function estimateGen(length, nodes) {
for (var i = 0; i < length; i++) {
const estimate = [];
let estimateVal = Math.random().toString(36).replace('0.','').slice(0,7);
estimate.push(estimateVal);
arr.push(estimate);
nodeGen(estimate, nodes)
}
}
// Adding x amount of nodes between 1 and 10 into each estimate sub array in their own objects.
function nodeGen(estimate, nodes) {
for (var i = 0; i < nodes; i++) {
let nodeID = Math.floor(Math.random() * 10) + 1;
estimate.push(nodeID);
}
}
// Calling the function and saying how many nodes per estimate we want.
estimateGen(5, 3);
console.log(arr);
From this code I now get the result:
[
[ 'p68xw8h', 5, 4, 6 ],
[ 'wn2yoee', 5, 4, 5 ],
[ '1w01tem', 9, 7, 4 ],
[ 'we3s53f', 8, 8, 8 ],
[ '5nrtp09', 3, 3, 8 ]
]
Would there be a way to count the number of times the values on the right appear and what 'estimate' ID at [0] it appears in?
Thank you.
First, let's redesign your input data and results to be a more useful format:
// input
[
{ nodes: [3, 4, 6], Estimate: '0jvyt8a' },
{ nodes: [4, 6, 3], Estimate: 'mc973fs' },
{ nodes: [4, 1, 3], Estimate: 'vwsfh8k' },
{ nodes: [4, 3, 5], Estimate: 'n6xzge3' },
{ nodes: [8, 7, 1], Estimate: 'v0jn7bh' }
];
// result
{
1: ["vwsfh8k", "v0jn7bh"],
3: ["0jvyt8a", "mc973fs", "vwsfh8k", "n6xzge3"],
...
]
Then the code would be:
const input = [
{ nodes: [3, 4, 6], Estimate: '0jvyt8a' },
{ nodes: [4, 6, 3], Estimate: 'mc973fs' },
{ nodes: [4, 1, 3], Estimate: 'vwsfh8k' },
{ nodes: [4, 3, 5], Estimate: 'n6xzge3' },
{ nodes: [8, 7, 1], Estimate: 'v0jn7bh' }
];
const result = {};
input.forEach(({
nodes,
Estimate: e
}) =>
nodes.forEach(n => {
if (!result[n]) {
result[n] = [];
}
result[n].push(e);
})
);
console.log(result);
You can create the data with:
// Making an empty array
const arr = [];
//Generating the estimate IDs and placing them all in their own object in their own array.
function estimateGen(length, nodes) {
for (var i = 0; i < length; i++) {
let estimateVal = Math.random().toString(36).replace('0.', '').slice(0, 7);
const estimate = {
Estimate: estimateVal,
nodes: []
}
arr.push(estimate);
nodeGen(estimate, nodes)
}
}
// Adding x amount of nodes between 1 and 10 into each estimate sub array in their own objects.
function nodeGen(estimate, nodes) {
for (var i = 0; i < nodes; i++) {
let nodeID = Math.floor(Math.random() * 10) + 1;
estimate.nodes.push(nodeID);
}
}
// Calling the function and saying how many nodes per estimate we want.
estimateGen(5, 3);
console.log(arr);
I've reformatted your array. The output is different, but you can still use it.
var arr = [
{ '0': 3 , '1': 4 , '2': 6 , 'Estimate:': '0jvyt8a' },
{ '0': 4 , '1': 6 , '2': 3 , 'Estimate:': 'mc973fs' },
{ '0': 4 , '1': 1 , '2': 3 , 'Estimate:': 'vwsfh8k' },
{ '0': 4 , '1': 3 , '2': 5 , 'Estimate:': 'n6xzge3' },
{ '0': 8 , '1': 7 , '2': 1 , 'Estimate:': 'v0jn7bh' }
];
var num = [1, 3, 4, 5, 6, 7, 8];
num = num.map(n =>
[n, ...(
arr.filter(a => [0, 1, 2].some(nm => a[nm] === n))
.map(v => v["Estimate:"])
)]);
console.log(num);
For getting a counting object you could take the values as key and estimates as key for the count of same values.
function estimateGen(length, nodes) {
var array = [];
for (var i = 0; i < length; i++) {
array.push([Math.random().toString(36).replace('0.','').slice(0,7), ...nodeGen(nodes)]);
}
return array;
}
function nodeGen(nodes) {
var result = [];
for (var i = 0; i < nodes; i++) {
result.push(Math.floor(Math.random() * 10) + 1);
}
return result;
}
function count(data) {
return data.reduce((r, [estimate, ...values]) => {
values.forEach(v => {
r[v] = r[v] || {};
r[v][estimate] = (r[v][estimate] || 0) + 1;
});
return r;
}, {});
}
var temp = estimateGen(5, 3);
console.log(temp);
console.log(count(temp));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have an array objects that hold an id and a name
const stages = [{
id: 1,
name: ''
}, {
id: 2,
name: ''
}, {
id: 3,
name: ''
}, {
id: 4,
name: ''
}, {
id: 5,
name: ''
}, {
id: 6,
name: ''
}, {
id: 7,
name: ''
}, {
id: 8,
name: ''
}];
Further I have an array that holds numbers.
const indexPositions = [0, 1, 2, 2, 2, 3, 2, 0];
I want to create a third array that holds arrays. Each number in distances represents the index of the current array within the array.
If the current array does not exist yet I want to create it first. Obviously I have to create new arrays until I get to this index position.
Example:
My array is empty at start. The first index position is 0 so I have to create a new array for this. The next index position is 3 so I have to create more arrays until I have 4 arrays.
All I want to do is to push the stage to its correct level index position. The result of this example would be
const levels = [
[stage1, stage8],
[stage2],
[stage3, stage4, stage5, stage7],
[stage6]
];
Currently my code looks this
$(document).ready(() => {
const levels = []; // the array containing the arrays
stages.forEach((stage, stageIndex) => {
const indexPosition = indexPositions[stageIndex];
const positionDifference = indexPosition - levels.length;
if (positionDifference > 0) {
for (let i = 0; i < positionDifference; i++) { // fill up with empty arrays
levels.push([]);
}
}
levels[indexPosition].push(stage);
});
});
I get this error Uncaught TypeError: Cannot read property 'push' of undefined and this happens because the indexPosition is out of bounds. If the positionDifference is 0 no array gets created but in the beginning the array is empty.
I tried setting levels.length to -1 if it is 0 but I still get the error if the difference is 1, I create one array at position 0 and want to access position 1.
How can I create an empty array if it does not exist?
While I do not fully understand what you want to do, checking existence of an array element is simple, one way of doing that is coercing it to boolean:
const thing=[];
function addElem(where,what){
if(!thing[where]) // <- here
thing[where]=[];
thing[where].push(what);
}
addElem(2,1);
addElem(2,2);
addElem(2,3);
addElem(5,1);
console.log(thing);
(The indices are deliberately non-continuous, because that does not matter: JavaScript arrays are sparse)
You could use a single loop and add an array for the index if not exists. Then push the wanted value.
var stages = [{ id: 1, name: '' }, { id: 2, name: '' }, { id: 3, name: '' }, { id: 4, name: '' }, { id: 5, name: '' }, { id: 6, name: '' }, { id: 7, name: '' }, { id: 8, name: '' }],
indexPositions = [0, 1, 2, 2, 2, 3, 2, 0],
result = stages.reduce((r, o, i) => {
var index = indexPositions[i];
r[index] = r[index] || []; // take default value for falsy value
r[index].push('stage' + o.id); // instead of string take object
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You actually were very close! You have a very small issue in your code.
$(document).ready(() => {
const levels = []; // the array containing the arrays
stages.forEach((stage, stageIndex) => {
const indexPosition = indexPositions[stageIndex];
const positionDifference = indexPosition - levels.length + 1; //YOU DID NOT ADD 1 HERE
if (positionDifference > 0) {
for (let i = 0; i < positionDifference; i++) { // fill up with empty arrays
levels.push([]);
}
}
levels[indexPosition].push(stage);
});
});
When you were calculating the positionDifference, you did not add 1 causing the problem when indexPosition equaled 0 and the for loop did not run and no new arrays were pushed. Just adding one fixed the problem :-)
Maybe this isn't the right place to ask this but I need a advice since I'm stuck on this. I have this code:
$(document).ready(function(){
var i = 0, j = 0,
manufacturerIds = [1,2,3,4,5,6,7],
countryIds = [1,2,3,4,5,6,7,8,9,10],
result = [];
for (i; i < manufacturerIds.length; i++) {
for (j; j < countryIds.length; j++) {
result.push({
i: {
idMan: manufacturerIds[i],
idCtr: [] // stuck on this point, don't know
// where to go from here and don't know
// if I'm doing things right
}
});
}
}
});
And I'm trying to return a output like this:
[
{
"0": {
"idMan": 1,
"idCtr": [
1,
2,
3,
4,
5
]
},
"1": {
"idMan": 2,
"idCtr": [
1,
2,
3,
4,
5
]
},
"2": {
"idMan": 3,
"idCtr": [
1,
2,
3,
4,
5
]
}
}
]
Can any give me some advice? Or help?
NOTE: I'm not sure this is the right or best way but I'm trying to build some kind of structure where I can differentiate each item on the object|array, why? Because I'll need to add new element to it. For example, this ouput will be valid too:
[
{
"0": {
"idMan": 1,
"idCtr": [
1,
2
]
},
"1": {
"idMan": 1,
"idCtr": [
1,
4,
5
]
},
"2": {
"idMan": 1,
"idCtr": [
3
]
}
}
]
Then having this I think will be easy to add new idCtr right? By accesing someVar[X].idCtr.push(newVal);. BTW, I write some var examples but the truth is those values are dynamic, just a start point for you to get the idea behind my doubt
I believe this is more along the lines of what you are wanting
var i = 0,
j = 0,
manufacturerIds = [1, 2, 3, 4, 5, 6, 7],
countryIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
result = [];
for (i; i < manufacturerIds.length; i++) {
/* create basic object*/
var item = {};
item[i] = {idMan: manufacturerIds[i],idCtr: []};
/* now push country Ids*/
for (var j=0;; j < countryIds.length; j++) {
item[i].idCtr.push(countryIds[j]);
}
/* finished creating object*/
result.push(item);
}
DEMO
You can use JSON.stringify() to convert the result to JSON. There is another problem with i: {} try something like this:
$(document).ready(function(){
var i = 0, j = 0,
manufacturerIds = [1,2,3,4,5,6,7],
countryIds = [1,2,3,4,5,6,7,8,9,10],
result = [];
for (i; i < manufacturerIds.length; i++) {
var obj = {};
obj[i] = { idMan: manufacturerIds[i], idCtr: [] };
for (j; j < countryIds.length; j++) {
obj[i].idCtr.push(countryIds[j]);
}
result.push(obj);
}
var data = JSON.stringify(result);
});
I have an array of objects that looks similar to this:
[
{
id : 1,
position: false
},
{
id: 2,
position: false
},
{
id: 3,
position: 4
},
{
id: 4,
position: false
},
{
id: 5,
position: 2
},
{
id: 6,
position: 5
},
{
id: 7,
position: 3
},
{
id: 8,
position: 1
},
]
I would like to sort this array using the position property (ascending) of each object so that the array looks like this:
[
{
id: 8,
position: 1
},
{
id: 5,
position: 2
},
{
id: 7,
position: 3
},
{
id: 3,
position: 4
},
{
id: 6,
position: 5
},
{
id: 1,
position: false
},
{
id: 2,
position: false
},
{
id: 4,
position: false
}
]
The idea is only to move the objects with a position that isnt false to the top without affecting the order of the rest of the objects with a position set to false.
Seems easy enough, right? I've tried to approach this problem in so many ways but nothing seems to work reliably. Hopefully someone can help me get my head around how to properly go about this.
Help me Stack Overflow, you're my only hope.
I tried to add a bunch of comments to help you follow my ideas.
This is implemented in an imperative style, and (I hope) can help with illustrating some ideas for how to approach similar problems.
I used your sample data set, and reproduced the result you were looking for.
I hope this is helpful and that it can be modified to suit whatever data you require.
I also pasted the text here.
var deepSort = function(arr){
var i;
var hasPositionKey = [];
var noPositionKey = [];
var nestedObj;
var positions = [];
var loggingPositions = {};
var positionSortedObjects = [];
// iterate through the array of objects
for(i = 0; i < arr.length; i++){
// set a variable for the individual object being considered
nestedObj = arr[i];
// if that object has a position of false
if(nestedObj.position === false){
// push false object into the array of false position objects
noPositionKey.push(nestedObj);
}
// if the object has a numbered position
if(typeof nestedObj.position === 'number'){
// push numbered position to the array of numbered position objects
hasPositionKey.push(nestedObj);
}
}
// iterate through the array of objects with positions
for(i = 0; i < hasPositionKey.length; i++){
// set a variable for the individual object being considered
nestedObj = hasPositionKey[i];
// push only the position number into an array to track positions
positions.push(nestedObj.position);
// add a key value pair of position:id to an object
loggingPositions[nestedObj.position] = nestedObj.id;
}
// sort the array that stores the positions of the non-false objects
positions.sort();
// iterate through that array and construct a final array of objects by sorted position
for(i = 0; i < positions.length; i++){
// set a variable for the positions, as encountered in order:
var num = positions[i];
// set a key for the object to be constructed
var key = loggingPositions[num];
// set a value for the object to be constructed
var value = num;
// construct a result object with object literal notation:
var result = {
id: key,
position: value
};
// push the constructed objects into the positionSortedObjects array
positionSortedObjects.push( result );
}
// return a concatenated array of the positionSortedObjects + the noPositionKey objects
return (positionSortedObjects.concat(noPositionKey));
};
var sample = [
{
id : 1,
position: false
},
{
id: 2,
position: false
},
{
id: 3,
position: 4
},
{
id: 4,
position: false
},
{
id: 5,
position: 2
},
{
id: 6,
position: 5
},
{
id: 7,
position: 3
},
{
id: 8,
position: 1
}
];
deepSort(sample);
The easy way to sort your data would be to use the use the Array.sort() function. First check if the position of object 2 is false, if so return -1 to float object 1 to top. Do the opposite for object 1. If both are not false, do an integer compare.
var data = [
{ id: 1, position: false },
{ id: 2, position: false },
{ id: 3, position: 4 },
{ id: 4, position: false },
{ id: 5, position: 2 },
{ id: 6, position: 5 },
{ id: 7, position: 3 },
{ id: 8, position: 1 }
];
data.sort(function (a, b) {
posa = a.position;
posb = b.position;
if (!posb) return -1;
if (!posa) return 1;
return posa - posb;
});
console.log(data);
But this solution may not be the best because Array.sort() does not require a standard according to ECMA International:
Excerpt below taken from ECMAScript Language Specification, 2011, p.129
15.4.4.11 Array.prototype.sort (comparefn)
The elements of this array are sorted. The sort is not necessarily stable (that is, elements that compare equal do not necessarily remain in their original order). If comparefn is not undefined, it should be a function that accepts two arguments x and y and returns a negative value if x < y, zero if x = y, or a positive value if x > y.
A work around for this would be for you to devise your own sorting algorithm. Preferably a merge or quick-sort algorithm. Below is an implementation of the quick-sort algorithm used to sort the data as intended. Note: There is a link to JSFiddle at the bottom of this response.
/**
* Add a swap function to the Array object.
* #param a Object a.
* #param b Object b.
*/
Array.prototype.swap = function (a, b) {
var tmp = this[a];
this[a] = this[b];
this[b] = tmp;
};
/**
* A utility function to print out HTML to the screen in case the user's
* console is not enabled or present.
* #param message The message to print to the screen.
*/
var trace = function (message) {
id = 'trace';
t = $('#' + id);
if (t.length < 1) t = $('<div>', {
'id': id
}).appendTo($('body'));
t.append($('<p>', {
'html': message
}));
};
/**
* An implementation of the quick-sort algorithm that allows the user to
* use a custom comparator with the following signature
* {#code function(a, b) } which will return an integer value to determine
* ordering.
* #param array The array to be sorted.
* #param comparator The custom comparator function.
*/
var quickSort = function (array, comparator) {
var __internal_compare__ = function compare(a, b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
};
comparator = comparator || __internal_compare__;
var qsort = function (array, begin, end, comparator) {
if (end - 1 > begin) {
var pivot = begin + Math.floor(Math.random() * (end - begin));
pivot = partition(array, begin, end, pivot, comparator);
qsort(array, begin, pivot, comparator);
qsort(array, pivot + 1, end, comparator);
}
};
var partition = function (array, begin, end, pivot, comparator) {
var piv = array[pivot];
array.swap(pivot, end - 1);
var store = begin;
var ix;
for (ix = begin; ix < end - 1; ++ix) {
if (piv != undefined && comparator(piv, array[ix]) < 0) {
array.swap(store, ix);
++store;
}
}
array.swap(end - 1, store);
return store;
};
qsort(array, 0, array.length, comparator);
};
// The custom compare function to be used on the array of data below
// in the quick-sort function.
var compare = function (a, b) {
var isBoolAndFalse = function (val) {
return typeof val === 'boolean' && !val;
};
if (a == b) return 0;
var posa = a.position;
var posb = b.position;
var cona = isBoolAndFalse(posb);
var conb = isBoolAndFalse(posa);
if (cona && conb) {
var ida = a.id;
var idb = b.id;
return idb - ida;
}
if (conb) return -1;
if (cona) return 1;
return posb - posa;
};
/**
* Main procedure follows:
*/
var data = [
{ id: 1, position: false },
{ id: 2, position: false },
{ id: 3, position: 4 },
{ id: 4, position: false },
{ id: 5, position: 2 },
{ id: 6, position: 5 },
{ id: 7, position: 3 },
{ id: 8, position: 1 }
];
quickSort(data, compare);
trace(JSON.stringify(data, undefined, 2));
Output:
[
{
"id": 8,
"position": 1
},
{
"id": 5,
"position": 2
},
{
"id": 7,
"position": 3
},
{
"id": 3,
"position": 4
},
{
"id": 6,
"position": 5
},
{
"id": 1,
"position": false
},
{
"id": 2,
"position": false
},
{
"id": 4,
"position": false
}
]
You can test the above code out by using the following JSFiddle Demo. I hope this clears thing up for you.