I have this array with objects that look like this
{
n: 15,
color: "red"
}
I am trying to sort it with the below function
async insertionSort() {
let len = this.array.length;
let value;
let i;
let j;
//let current;
// let arr = this.array;
for (i = 0; i < len; i++) {
value = this.array[i].n;
//current = this.array[i];
for (j = i - 1; j > -1 && this.array[j].n > value; j++) {
//arr[j + 1] = arr[j];
// HF.arraySwap(this.array, this.array[j + 1], this.array[j]);
this.array[j + 1] = this.array[j];
}
// arr[j + 1] = value;
HF.arraySwap(this.array, this.array[j + 1], this.array[i]);
await HF.sleep();
}
}
** I cant use array.sort(...) because i am trying to make a visualization of the algorithm, i am using objects in order to change the color of the bars i am rendering on the screen **
When i hit the second for loop i get an error of "Cannot read property 'n' of undefined", when i run it with just numbers it works fine but when i try it with objects it gives the error.I know now i am running out of the array, is there a way i can overcome this and still sort the array of objects? Also, i am using VueJS to display all of this
Try against this.array[i].n write this.array[i][n]
And against this.array[j].n write this.array[j][n]
On the first iteration i=0, you start second loop with value j=i-1 which is -1. Array doesn't contain item with index -1: array[-1] is undefined. As soon as JavaScript can compare variables of different types it works with numbers because comparison of number and undefined won't trigger an error
By the way you can use Array.proototype.sort method, it will look like:
console.log(myArr.sort((a,b) => a.n - b.n))
<script>
const myArr = [
{ n: 1, color: "red" },
{ n: 44, color: "orange" },
{ n: 13, color: "yellow" },
{ n: 8, color: "green" },
{ n: 2, color: "blue" }
];
</script>
Is there any reason why not use sort method like this?:
const arr = [
{ n: 10, color: "red" },
{ n: 20, color: "yellow" },
{ n: 15, color: "black" },
{ n: 7, color: "white" },
{ n: 23, color: "blue" }
];
const ascSorted = arr.sort((a, b) => a.n - b.n);
const descSorted = arr.sort((a, b) => b.n - a.n);
console.log(ascSorted);
// [
// { n: 7, color: "white" },
// { n: 10, color: "red" },
// { n: 15, color: "black" },
// { n: 20, color: "yellow" },
// { n: 23, color: "blue" }
// ];
Related
I need help in transforming data in a particular way to plot a graph. The data which I get from API is a different format. Please guide me on how to transform it
const demo = [
{
label: 'ABC',
vMini: 28,
vMaxi: 56,
dMini: 2,
dMaxi: 50,
},
{
label: 'BCD',
vMini: 2,
vMaxi: 56,
dMini: 3,
dMaxi: 50,
},
];
end result which i want is
[
{
section: "vMini",
"ABC": 28,
"BCD": 2,
},
{
section: "vMaxi",
"ABC": 56,
"BCD": 56
}
{
section: "dMini",
"ABC": 2,
"BCD": 3,
},
{
section: "dMaxi",
"ABC": 50,
"BCD": 50
}
]
I have started working on it and got confused with second loop.
for (let i = 0; i < demo.length; i += 1) {
for (let j in demo[i]) {
if (j === 'label') {
}
}
}
This one is a bit tricky with the way the data is structured, but you should be able to do this with array.reduce, like so:
const demo = [{label:"ABC",vMini:28,vMaxi:56,dMini:2,dMaxi:50},{label:"BCD",vMini:2,vMaxi:56,dMini:3,dMaxi:50}];
// get array of keys, and create a new object for each one except label
// ["label", "vMini", "vMaxi", "dMini", "dMaxi"]
let results = Object.keys(demo[0]).reduce((res, key) => {
if (key === "label") { return res; }
else {
// for each item in demo, create a key for the label and grab the key's value
let newObj = demo.reduce((_res, obj) => {
_res[obj.label] = obj[key];
return _res;
}, {section: key})
// push the new object into the results array
res.push(newObj);
}
return res;
}, [])
console.log(results);
Using reduce() and Map()
const demo = [{label:"ABC",vMini:28,vMaxi:56,dMini:2,dMaxi:50},{label:"BCD",vMini:2,vMaxi:56,dMini:3,dMaxi:50}];
const resMap = demo.reduce((a, v) => {
let label = v.label
for (let k in v) {
if (k == 'label') continue
a.has(k) || a.set(k, { section: k })
let o = a.get(k)
o[label] = v[k]
}
return a
}, new Map())
const resArr = [...resMap.values()]
console.log(resArr)
I have a scenario, were need to compare treeObject1 and treeObject2 to determine the exact difference at property level and find the parent of modified node.
In below provided objects, I need to get output as color blue. Since the difference is at otherObj2.
treeObject1 = {
color: "red",
value: 10,
otherObj: {
color: "blue",
otherObj2: {
otherColor: "blue",
otherValue: 20,
}
}
}
treeObject2 = {
color: "red",
value: 10,
otherObj: {
color: "blue",
otherObj2: {
otherColor: "Green",
otherValue: 20,
}
}
}
If you want the key "otherObj" as well let me know, that can easily be added. Otherwise here is a working version of what you were looking for.
This uses a combination of Object.keys and every
treeObject1 = {
color: "red",
value: 10,
otherObj: {
color: "blue",
otherObj2: {
otherColor: "blue",
otherValue: 20,
}
}
}
treeObject2 = {
color: "red",
value: 10,
otherObj: {
color: "blue",
otherObj2: {
otherColor: "Green",
otherValue: 20,
}
}
}
const findParentNode = (obj1, obj2, parent = null) => {
if(parent === null) parent = obj2;
//since the structures are the same we only get keys from the first object
const keys = Object.keys(obj1);
let result = null;
//iterate through every key
keys.every(key=>{
//if it's an object... then we recall findParentNode (recursive)
if(obj1[key] instanceof Object){
result = findParentNode(obj1[key], obj2[key], obj2);
//If result from findParentNode is not null then a difference was found.
//Return false to stop the every method.
if(result !== null) return false;
}else if(obj1[key] !== obj2[key]){
//If the objects are different we found a difference
//Set the parent as the difference
result = parent;
return false;
}
//return true to keep on looping
return true;
});
//return the result
return result;
}
console.log(findParentNode(treeObject1, treeObject2));
** note that the above snippet will return "null" if nothing was found. **
You could use a nested approach for objects and by checking the values.
function getDiffParents(object1, object2, parent = {}) {
return Object.assign(...Object.entries(object1).map(([k, v]) => v && typeof v === 'object'
? getDiffParents(v, object2[k], object1)
: v === object2[k]
? {}
: parent
));
}
var treeObject1 = { color: "red", value: 10, otherObj: { color: "blue", otherObj2: { otherColor: "blue", otherValue: 20 } } },
treeObject2 = { color: "red", value: 10, otherObj: { color: "blue", otherObj2: { otherColor: "Green", otherValue: 20 } } };
console.log(getDiffParents(treeObject1, treeObject2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I am trying to loop through my json value obtain from my server which is like this:
[
{
below_min: [
{
y: 0,
label: "Bhagalpur",
color: "Red"
},
{
y: 0,
label: "Gopalganj",
color: "Red"
}
]
},
{
min: [
{
y: 0.2,
label: "Samastipur",
color: "Orange"
},
{
y: 0.3,
label: "Saran",
color: "Orange"
}
}
]
}
]
I am using this loop code to get the value of my below_min array:
for (let index = 0; index < res.length; index++) {
const element = res[index];
console.log(element.below_min);
// const u = element.below_min
for (let index = 0; index < element.below_min.length; index++) {
const h = element.below_min[index];
}
}
but I am getting error:
ERROR TypeError: Cannot read property 'length' of undefined
I have tried few things such as when I am trying to see what is this below_min as type of I am seeing this as an object. My question is what is wrong with my code.
Your Javascript Object literal has syntax issue. so i tried to correct it.
You can try the following code and get the idea about getting below_min correctly:
const res = [
{
below_min: [
{
y: 0,
label: "Bhagalpur",
color: "Red"
},
{
y: 0,
label: "Gopalganj",
color: "Red"
}
]
},
{
min: [
{
y: 0.2,
label: "Samastipur",
color: "Orange"
},
{
y: 0.3,
label: "Saran",
color: "Orange"
}
]
}
];
for (let index = 0; index < res.length; index++) {
const element = res[index];
if(element.below_min){
for (let minIndex = 0; minIndex < element.below_min.length; minIndex++) {
const h = element.below_min[minIndex];
console.log(h);
}
}
}
Your list contains a lot of elements that doesn't have below_min property and when you want to reach the property it will return undefined.
Let's have an object with some default settings:
var defaults = {
id: '',
x: 0,
y: 0,
width: 20,
height: 20,
styles: {
color: '#ffffff',
background_color: '#000000'
},
points: []
}
Then, we make our own object, which initially extends the default settings, and makes some changes:
var newObject = {
id: '1', // changed
x: 10, // changed
y: 10, // changed
width: 20,
height: 20,
styles: {
color: '#ffffff',
background_color: '#333333' // changed
},
points: [1, 2, 3]
}
Finally, we need an object, which contains only the values that changed from the default settings, like this:
var subtracted = {
id: '1',
x: 10,
y: 10,
styles: {
background_color: '#333333'
},
points: [1, 2, 3]
}
The algorithm needs to be recursive, there can be objects within objects. Here is what I have so far:
function subtract(a, b) {
var r = {};
// For each property of 'b'
// if it's different than the corresponding property of 'a'
// place it in 'r'
for (var key in b) {
if (typeof(b[key]) == 'object') {
if (!a[key]) a[key] = {};
r[key] = subtract(a[key], b[key]);
} else {
if (b[key] != a[key]) {
r[key] = a[key];
}
}
}
return r;
}
However, the recursion is not working for arrays, so "points" turns out as an empty object! typeof() detects it as an object and fails to clone its properties, somehow.
https://jsfiddle.net/gd8q1u18/1/
Your code is working. though there is one edit I made in it to make it recursive as well.
var defaults = {
id: '',
x: 0,
y: 0,
width: 20,
height: 20,
styles: {
color: '#ffffff',
background_color: '#000000'
},
points: []
}
var newObject = {
id: '1', // changed
x: 10, // changed
y: 10, // changed
width: 20,
height: 20,
styles: {
color: '#ffffff',
background_color: '#333333' // changed
},
points: [0, 1, 2] // changed
}
var subtracted = {
id: '1',
x: 10,
y: 10,
styles: {
background_color: '#333333'
}
}
function isSame(a, b) {
if (a.length != b.length) return false;
if (a.filter(function(i) {
return a.indexOf(i) < 0;
}).length > 0)
return false;
if (b.filter(function(i) {
return a.indexOf(i) < 0;
}).length > 0)
return false;
return true;
};
function subtract(a, b) {
var r = {};
// For each property of 'b'
// if it's different than the corresponding property of 'a'
// place it in 'r'
for (var key in b) {
if (Array.isArray(b[key])) {
if (!a[key]) a[key] = [];
if (!isSame(a[key], b[key]))
r[key] = a[key];
} else if (typeof(b[key]) == 'object') {
if (!a[key]) a[key] = {};
r[key] = subtract(a[key], b[key]);
} else {
if (b[key] != a[key]) {
r[key] = a[key];
}
}
}
return r;
}
console.log(subtract(newObject, defaults));
UPDATE: another approach a little bit more toward recursion. It runs through modifications so newObject can disregard some fields. It works with primitives too.
const equalArrays = (arr1, arr2) => arr1.length === arr2.length && arr1.every((element, index) => element === arr2[index])
// notice that equalArrays matters the order of the arrays' elements.
// If order doesn't matter, consider sorting both arrays first
const isObject = (obj) => obj instanceof Object && !(obj instanceof Array)
// notice that arrays are instance of Objects too
// an unwary consumer might mix arrays and objects with unpredictable results
const isArray = (arr) => arr instanceof Array
const getDifferences = (original, modified) => {
const areArrays = isArray(original) && isArray(modified)
const areObjects = isObject(original) && isObject(modified)
if (areObjects) {
let result = {}
for (const key of Object.keys(modified)) {
const diff = getDifferences(original[key], modified[key])
if (diff) result[key] = diff
}
return !!Object.keys(result).length && result
}
else if (areArrays && !equalArrays(original, modified)) return modified
else if (original !== modified) return modified
}
// notice that some variables and functions are there for readability and might be inlined
let defaults = {
id: '',
x: 0,
y: 0,
width: 20,
height: 20,
styles: {
color: '#ffffff',
background_color: '#000000'
},
points: []
}
let newObject = {
id: '1', // changed
x: 10, // changed
y: 10, // changed
width: 20,
height: 20,
styles: {
color: '#ffffff',
background_color: '#333333' // changed
},
points: [0, 1, 2] // changed
}
console.log(getDifferences(defaults, newObject))
I would take into account that some unwary consumer might mix arrays and objects.
const equalArrays = (arr1, arr2) => arr1.length === arr2.length && arr1.every((element, index) => element === arr2[index])
// notice that equalArrays matters the order of the arrays' elements.
// If order doesn't matter, consider sorting both arrays first
const isObject = (obj) => obj instanceof Object && !(obj instanceof Array)
// notice that arrays are instance of Objects too
// an unwary consumer might mix arrays and objects with unpredictable results
const isArray = (arr) => arr instanceof Array
const getDifferences = (obj1, obj2) => {
let obj3 = {}
for (const key of Object.keys(obj1)) {
const val1 = obj1[key]
const val2 = obj2[key]
const areArrays = isArray(val1) && isArray(val2)
const areObjects = isObject(val1) && isObject(val2)
if (areObjects) {
const diff = getDifferences(val1, val2)
if (diff) obj3[key] = diff
}
else if (areArrays && !equalArrays(val1, val2)) obj3[key] = val2
else if (val1 !== val2) obj3[key] = val2
}
return !!Object.keys(obj3).length && obj3
}
// notice that some variables and functions are there for readability and might be inlined
let defaults = {
id: '',
x: 0,
y: 0,
width: 20,
height: 20,
styles: {
color: '#ffffff',
background_color: '#000000'
},
points: []
}
let newObject = {
id: '1', // changed
x: 10, // changed
y: 10, // changed
width: 20,
height: 20,
styles: {
color: '#ffffff',
background_color: '#333333' // changed
},
points: [0, 1, 2] // changed
}
console.log(getDifferences(defaults, newObject))
I've got an array of nested objects
var arr = [{
tires: 2,
exterior: {
color: 'white',
length: 2,
width: 1
}
},{
tires: 4,
exterior: {
color: 'blue',
length: 5,
width: 3
}
},{
tires: 4,
exterior: {
color: 'white',
length: 2,
width: 3
}
}];
I want to create a function such that:
var findItems = function(arr, value){
// return array of found items
};
Some examples:
findItems(arr, 'white'); // [ arr[0], arr[2] ]
findItems(arr, 2); // [ arr[0], arr[2] ]
findItems(arr, {tires: 2}); // [ arr[0] ]
findItems(arr, {tires: 2, color: 'white'}); // [ ]
findItems(arr, {width: 1, color: 'white'}); // [ arr[0] ]
It's easy enough to find values for arrays with non-nested objects or if you know the exact level that you want to search in. But I'm not sure how to go about just finding "any value, anywhere" in an array. I quickly get into looping hell.
I can use Underscore if that helps.
I think it would be something like this:
function isObject(val) {
return Object(val) === val;
}
function search(val, ctx) {
var valIsObject = isObject(val);
return (function search(context) {
if(!isObject(context)) return val === context;
if(valIsObject && Object.keys(val).every(function(key) {
return context[key] === val[key];
})) return true;
return Object.keys(context).some(function(key) {
return search(context[key]);
});
})(ctx);
}
function findItems(arr, value){
return arr.filter(function(item) {
return search(value, item);
});
}
It should work reasonably well, except in some edge cases like circular references (infinite recursion) or descriptor properties (the code may call the getter on an incompatible object).