Moving an object inside an array ( Javascript) - javascript

I have an array of objects something like this
arr = [{"class":"section"},{"fieldGroup":[]},{"class":"col","name":"input"},{"class":"col","name":"dropdown"},{"class":"col","name":"date"},{"fieldGroup":[]},{"class":"col","name":"table"}]
Now I need to move the objects with "class":"col" inside its previous object which contains "fieldGroup"
So my desired output should be like this
arr = [{"class":"section"},{"fieldGroup":[{"class":"col","name":"input"},{"class":"col","name":"dropdown"},{"class":"col","name":"date"}]},{"fieldGroup":[{"class":"col","name":"table"}]}]
I have tried this piece of code
arr.forEach((item: any, index: number) => {
if (item.class === "col") {
arr[index - 1].fieldGroup.push(item);
arr.splice(index, 1);
}else {
return arr;
}
})
but getting an error saying cannot read property push of undefined
any help?

Your problem is that when you remove an item from your array using .splice() all the items in your arr shift down one index. For example, the item that used to be at index 3 will now be at index 2, the item that used to be at index 4 is will now be at index 3 etc. Your .forEach() loop doesn't take this shift into account, and so once you remove the item at index 2 with .splice() your index changes to 3 for the next iteration, but really, you need to look at index 2 again as your array items have shifted down an index. You can fix this by using a standard for loop and decrementing the index counter when you remove an item to look at th inded again:
const arr = [{"class":"section"},{"fieldGroup":[]},{"class":"col","name":"input"},{"class":"col","name":"dropdown"},{"class":"col","name":"date"},{"fieldGroup":[]},{"class":"col","name":"table"}];
for(let i = 0; i < arr.length; i++) {
const item = arr[i];
if (item.class === "col") {
arr[i - 1].fieldGroup.push(item);
arr.splice(i, 1);
i--;
}
}
console.log(arr);

try it ...
var arr = [{"class":"section","name":"input"},{"fieldGroupName":"one","fieldGroup":[]},{"class":"col","name":"input"},{"class":"col","name":"dropdown"},{"class":"section","name":"input"},{"fieldGroupName":"one","fieldGroup":[]},{"class":"col","name":"date"}]
arr.forEach((elm , index) =>{
if(elm.class == 'col'){
arr[1].fieldGroup.push(elm)
arr.splice(index, 1)
}
})
console.log(arr);

Try this:
var arr = [{
"class": "section"
},
{
"fieldGroup": []
},
{
"class": "col",
"name": "input"
},
{
"class": "dropdown"
},
{
"class": "date"
},
{
"fieldGroup": []
},
{
"class": "col",
"name": "table"
}
];
let fieldGroupPosition;
let finalArr = [];
let lastGroupPosition = null;
arr.forEach((item, index) => {
if (Array.isArray(item.fieldGroup)) {
finalArr.push({
fieldGroup: []
});
lastGroupPosition = finalArr.length - 1;
} else {
if (lastGroupPosition)
finalArr[lastGroupPosition].fieldGroup.push(item);
else
finalArr.push(item);
}
});
console.log(finalArr);

var a = [
{ class: "section" },
{ fieldGroup: [] },
{ class: "col", name: "input" },
{ class: "dropdown" },
{ class: "date" },
{ fieldGroup: [] },
{ class: "col", name: "table" },
];
var res = [];
var currFieldGroup = null;
for (var i in a) {
if ("fieldGroup" in a[i]) {
currFieldGroup = a[i];
res.push(a[i]);
} else if ("class" in a[i]) {
if (currFieldGroup) {
currFieldGroup.fieldGroup.push(a[i]);
} else {
res.push(a[i]);
}
}
}
console.log(res);

Related

how to get the value by the help of includes/index of

how to get the value in any way if key does match with "Item"
const data = [{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
}
];
/* How to get value if index found by Item */
for(let i = 0; i<data.length; i++) {
console.log(data[i].includes("Item"));
//Expecting phone and case
}
for-in allows you to loop through the keys in an object. Not to be confused with for-of, which loop through elements in an array.
const data = [{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
}
];
for(let datum of data)
{
for(let key in datum)
{
if(key.includes("Item"))
{
console.log(datum[key]);
}
}
}
In the simple way just change data[i].includes("Item") to data[i].keys().includes("Item").
BUT! Could we have some alternative data set here? For example:
const data = [{
"Item-55566": "phone",
"SomeKey: "Some Value",
123123: "Numeric key with value"
},
{
"Items-44555": "Case",
"Another-key": "Another value"
}
];
In this case you need to put some changes in your code to find correct keys & values:
for(let i = 0; i<data.length; i++) {
data[i].keys().forEach(v=>{
String(v).includes("Item") && console.log("Got index: ${i}, key: ${v}, value: ${data[i][v]}")
})
}
The for loop iterates through the two objects, so you can check to see whether the object has that particular property using hasOwnProperty()
const data = [
{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
},
];
/* How to get value if index found by Item */
for (let i = 0; i < data.length; i++) {
if (data[i].hasOwnProperty("Item-55566")) {
console.log(data[i]);
}
}
If you want to keep your loop (good that it's only one loop compared to other answers) you can do it with Object.keys and values:
const data = [{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
}
];
/* How to get value if index found by Item */
for(let i = 0; i<data.length; i++) {
if(Object.keys(data[i])[0].includes('Item')){
console.log(Object.values(data[i])[0]);
}
}
You can use .filter to filter all items of the data array which includes Item text.
Then you can use .map to render new value from each object comes from data array.
const data = [
{"Item-55566": "phone", },
{ "Items-44555": "Case",},
{ "Other-44555": "Nope",}];
var filteredItems = data.filter(item => Object.keys(item)[0].includes("Item"));
console.log(filteredItems.map(item => Object.values(item)[0]));
Refactor code - By using .reduce()
const data = [
{"Item-55566": "phone", },
{ "Items-44555": "Case",},
{ "Other-44555": "Nope",}];
var res = data.reduce((prev, curr) =>
{
var entries = Object.entries(curr)[0];
if(entries[0].includes("Item"))
prev.push(entries[1]);
return prev;
}, []);
console.log(res);

How to fInd the index from which distance of every requirements are closest to the Index

let blocks = [
{
gym:false,
school:true,
store:false,
},
{
gym:true,
school:false,
store:false,
},
{
gym:true,// and this contains gym
school:true,
store:false,
},
{
gym:false,
school:true, // this block is the answer as I can find all three requirements near to this index above and below index;
store:false,
},
{
gym:false,
school:true, // this contains store
store:true,
}
]
let filter = ['school','gym','store'];
Eg. Here the correct index is 3 as 2,3,4 index fulfilled all the requirements element. We could have n number of requirements and n number of elements.
Maybe like this?
Not sure what you want to do if the filter array has 4 items? If you then find the items you want at indexes 1, 2, 3, 4 - do you return index 2 or 3 or 2.5, for example?
Also, if you have your filter array as it currently is but you find two of the items at index 2 and the other at index 3 - do you return 2 or 3 or 2.5? (see second code snippet)
For now, I just return the dictionary and you can decide how to return your index.
let blocks = [
{
gym:false,
school:true,
store:false,
},
{
gym:true,
school:false,
store:false,
},
{
gym:true,// and this contains gym
school:true,
store:false,
},
{
gym:false,
school:true, // this block is the answer as I can find all three requirements near to this index above and below index;
store:false,
},
{
gym:false,
school:true, // this contains store
store:true,
}
]
let filter = ['school','gym','store'];
function findIndex(blocks, filter) {
const filterLen = filter.length;
const trackingObj = filter.reduce((agg,obj) => {
agg[obj] = [];
return agg;
}, {});
let foundIdx = null;
outerLoop: for (let idx in blocks) {
const obj = blocks[idx];
for (let key in trackingObj) {
const val = trackingObj[key];
// reset the obj key if any idx are "too far away"
if (val.length > 0) {
trackingObj[key] = val.filter(v => v > (idx - filterLen));
}
}
for (let key of filter) {
if (obj[key] == true) {
// save the index into the obj
trackingObj[key].push(parseInt(idx));
}
}
for (let key in trackingObj) {
const val = trackingObj[key];
if (val.length == 0) {
continue outerLoop;
}
}
// will only reach if all keys of trackingObj are not empty:
foundIdx = idx; // not sure what index you expect to return
break;
}
// return foundInd; // not sure what index you expect to return
return trackingObj;
}
console.log(findIndex(blocks, filter));
returns:
{
"school": [2, 3, 4],
"gym": [2],
"store": [4]
}
Here is another example to show what I meant earlier:
let blocks = [
{
gym:false,
school:false,
store:false,
},
{
gym:false,
school:false,
store:false,
},
{
gym:true,// this contains gym
school:true, // and school
store:false,
},
// do I return 2 or 3 or 2.5?
{
gym:false,
school:true, // this contains school
store:true, // and store
},
{
gym:false,
school:true,
store:true,
}
]
let filter = ['school','gym','store'];
function findIndex(blocks, filter) {
const filterLen = filter.length;
const trackingObj = filter.reduce((agg,obj) => {
agg[obj] = [];
return agg;
}, {});
let foundIdx = null;
outerLoop: for (let idx in blocks) {
const obj = blocks[idx];
for (let key in trackingObj) {
const val = trackingObj[key];
// reset the obj key if any idx are "too far away"
if (val.length > 0) {
trackingObj[key] = val.filter(v => v > (idx - filterLen));
}
}
for (let key of filter) {
if (obj[key] == true) {
// save the index into the obj
trackingObj[key].push(parseInt(idx));
}
}
for (let key in trackingObj) {
const val = trackingObj[key];
if (val.length == 0) {
continue outerLoop;
}
}
// will only reach if all keys of trackingObj are not empty:
foundIdx = idx; // not sure what index you expect to return
break;
}
// return foundInd; // not sure what index you expect to return
return trackingObj;
}
console.log(findIndex(blocks, filter));
returns this and I am not sure if the return idx should be 2, 2.5 or 3?:
{
"school": [2, 3],
"gym": [2],
"store": [3]
}

Array of objects how do i check for deeply nested text string duplicates & remove from array?

I have an array of objects
Deep inside those objects is a text string
I want to check if other objects in the same array have the same text string / are duplicates.
Then i need a new array with those duplicates removed.
I thought this would be quite simple but it's been testing my intellect for two days now.
const arr = [
{..obj 1}
{..obj 2}
{..obj 3}
{
id: 4,
uid: 24872-2847-249249892842,
tags: ['some', 'stuff'],
type: "blogpage",
href: "https://link-to-stuff",
first_publication_date: "2020-02-12T16:05:04+0000",
last_publication_date: "2020-02-18T21:52:06+0000",
data: {
...some stuff
heading: [
{ type: "heading1", text: "Here Is My Text I Need To Check Duplicates
Of"}
]
}
}
{..obj 5}
{..obj 6}
{..obj 7}
{..obj 8}
{..obj 9}
{..obj 10}
]
I figured something like:
filterOutDuplicates = (blogIndexContent) => {
let arr = blogIndexContent.pages;
let results = [];
arr.map(each => {
if (!results || !results.length) {
results.push(each);
} else {
for (let i = 0; i < results.length; i++) {
const headline = results[i].data.heading[0].text;
if (headline === each.data.heading[0].text) {
return;
} else {
return results.push(each);
}
}
}
})
console.log('Results :', results); // <-- this just gives me the same 9 blog stories again, no duplicates removed.
}
What am i doing wrong guys?
If you dont mind using lodash, it could be easily solved using _.uniqBy
const withoutDups = _.uniqBy(arr, 'data.heading[0].text')
Try this
const arr = [
{
id: 4,
data: {
heading: [
{
type: "heading1",
text: "Here Is My Text I Need To Check Duplicates Of"
}
]
}
},
{
id: 5,
data: {
heading: [
{
type: "heading1",
text: "Here Is My Text I Need To Check Duplicates Of"
}
]
}
},
{
id: 6,
data: {
heading: [
{
type: "heading1",
text: "Not Duplicates"
}
]
}
}
];
const withoutDuplicates = arr.reduce(
(prev, curr) =>
prev
.map(d => d["data"]["heading"][0]["text"])
.includes(curr["data"]["heading"][0]["text"])
? [curr]
: [...prev, curr],
[]
);
console.log(withoutDuplicates);
Slight changes to your code
1) remove using map, have loop over array.
2) Build the uniq object with keys. (Here headline is what we want)
3) Add to results array only when key is not in uniq
let arr = blogIndexContent.pages;
let results = [];
const uniq = {};
for (let i = 0; i < arr.length; i++) {
const headline = arr[i].data.heading[0].text;
if (!(headline in uniq)) {
results.push(each);
uniq[each] = 1;
}
}
console.log("Results :", results);
This should work for you:
filterOutDuplicates = blogIndexContent => {
let arr = blogIndexContent.pages
const result = []
arr.forEach(each => {
if (result.length === 0) {
result.push(each)
}
else {
const headline = each.data.heading[0].text
let found = false
for (let i = 0; i < result.length; i++) {
if (result[i].data.heading[0].text === headline) {
found = true
break
}
}
if (!found) {
result.push(each)
}
}
})
console.log('Results :', results)
}

How to find object by id in array of objects?

I have this json file:
var data = [{
"id": 0,
"parentId": null,
"name": "Comapny",
"children": [
{
"id": 1235,
"parentId": 0,
"name": "Experiences",
"children": [
{
"id": 3333,
"parentId": 154,
"name": "Lifestyle",
"children": []
},
{
"id": 319291392,
"parentId": 318767104,
"name": "Other Experiences",
"children": []
}
]
}
]
}];
I need to find object by id. For example if need to find an object with id:319291392, I have to get:
{"id": 319291392,"parentId": 318767104,"name": "Other Experiences","children": []}
How can I do that?
I tried to use this function:
function findId(obj, id) {
if (obj.id == id) {
return obj;
}
if (obj.children) {
for (var i = 0; i < obj.children.length; i++) {
var found = findId(obj.children[i], id);
if (found) {
return found;
}
}
}
return false;
}
But it doesn't work as it's an array of objects.
If your starting point is an array, you want to invert your logic a bit, starting with the array rather than with the object:
function findId(array, id) {
var i, found, obj;
for (i = 0; i < array.length; ++i) {
obj = array[i];
if (obj.id == id) {
return obj;
}
if (obj.children) {
found = findId(obj.children, id);
if (found) {
return found;
}
}
}
return false; // <= You might consider null or undefined here
}
Then
var result = findId(data, 319291392);
...finds the object with id 319291392.
Live Example
This should work for you:-
var serachById = function (id,data) {
for (var i = 0; i < data.length; i++) {
if(id==data[i].id)
return data[i];
if(data[i].children.length>0)
return serachById(id,data[i].children);
};
return null;
}
console.log(serachById(0,data));
Here is another simple solution using object notation.
This solution will work even if you decide to get rid of teh array and use object notation later on. so the code will remain the same.
It will also support the case when you have element with no children.
function findId(obj, id) {
var current, index, reply;
// Use the object notation instead of index.
for (index in obj) {
current = obj[index];
if (current.id === id) {
return current;
}
reply = findId(current.children, id);
if (reply) {
return reply;
}
// If you reached this point nothing was found.
console.log('No match found');
}
}
console.log(findId(data, 319291392));
do it so:
for (var obj in arr) {
if(arr[obj].id== id) {
console.log(arr[obj]);
}
}

Loop through multidimensional array with all unique IDs

I have a multidimensional array but the ID's are unique across parents and children, so I have a problem looping through using a for loop. The problem is that I cannot seem to grab the ID of the children. How do you think I should handle this?
var Options = [
{
id: 0,
children: []
},
{
id: 2,
children: []
},
{
id: 3,
children: [
{
id: 4,
children: []
},
{
id: 5,
children: []
},
{
id: 6,
children: []
}
]
},
{
id: 7,
children: [
{
id: 8,
children: []
},
{
id: 9,
children: []
}
]
}
];
I have kept the code concise for the sake of brevity. What I am trying to do is iterate through the array to compare ID's.
This does not look like a "multidimensional array", but rather like a tree. Looping one level can be done with a simple for-loop:
for (var i=0; i<Options.length; i++) // do something
To loop the tree in-order, you will need a recursive function:
function loop (children, callback) {
for (var i=0; i<children.length; i++) {
callback(children[i]);
loop(children[i].children, callback);
}
}
loop(Options, console.log);
To get all children by their id, so that you can loop through the ids (regardless of the tree structure), use a lookup table:
var nodesById = {};
loop(Options, function(node) {
nodesById[node.id] = node;
});
// access:
nodesById[4];
…and to loop them sorted by id, you now can do
Object.keys(nodesById).sort(function(a,b){return a-b;}).forEach(function(id) {
var node = nodesById[id];
// do something
});
How about recursion?
var findById = function (arr, id) {
var i, l, c;
for (i = 0, l = arr.length; i < l; i++) {
if (arr[i].id === id) {
return arr[i];
}
else {
c = findById(arr[i].children, id);
if (c !== null) {
return c;
}
}
}
return null;
}
findById(Options, 8);
Ah, use recursion :D
var Options = "defined above";//[]
var OptionArray = []; //just as an example (not sure what you want to do after looping)
(function looper(start){
for( var i = 0, len = start.length; i < len; i++ ){
var currentOption = start[i];
if( currentOption.id > 3 ){//could be more complex
OptionArray.push(currentOption);
}
if( currentOption.children.length > 0 ){
looper(currentOption.children);
}
}
})(Options);

Categories