Related
So I have an array like this. Like array containing an array of objects.
posts = [
[
{
"id": 2,
"info": "This is some information"
},
{
"id": 3,
"info": "This is the other information"
}
],
[
{
"id": 2,
"info": "This is a duplicated id I want to remove"
},
{
"id": 4,
"info": "This information is safe"
}
]
]
I want to get the elements from each array and create a new array that only has the objects at the same time removing duplicated ids.
What am trying to achieve is something like
posts = [
{
"id": 2,
"info": "This is some information"
},
{
"id": 3,
"info": "This is the other information"
},
{
"id": 4,
"info": "This information is safe"
}
]
This is the code I have so far
id = ids.map(val => {
for(let i in val) {
console.log(val)
}
return something
})
I keep getting undefined values. I have tried forEach, for loop.
Any help would be much appreciated. Thanks
Use flat to get a flattened array of objects, and then loop over the array. If the current object's id can't be found in an object in the output array push that object.
const posts=[[{id:2,info:"This is some information"},{id:3,info:"This is the other information"}],[{id:2,info:"This is a duplicated id I want to remove"},{id:4,info:"This information is safe"}]];
const out = [];
for (const obj of posts.flat()) {
const found = out.find(f => obj.id === f.id);
if (!found) out.push(obj);
}
console.log(out);
You could use .flat() and then .filter():
const posts = [
[
{
id: 2,
info: 'This is some information',
},
{
id: 3,
info: 'This is the other information',
},
],
[
{
id: 2,
info: 'This is a duplicated id I want to remove',
},
{
id: 4,
info: 'This information is safe',
},
],
];
const newPosts = posts.flat().filter((x, i, self) => i === self.findIndex((y) => x.id === y.id));
console.log(newPosts);
Another potential (and more optimal) solution could be this using .reduce():
const posts = [
[
{
id: 2,
info: 'This is some information',
},
{
id: 3,
info: 'This is the other information',
},
],
[
{
id: 2,
info: 'This is a duplicated id I want to remove',
},
{
id: 4,
info: 'This information is safe',
},
],
];
const newPosts = Object.values(posts.flat().reduce((acc, curr) => {
return {
...acc,
...(!acc[curr.id] ? { [curr.id]: curr } : undefined),
};
}, {}));
console.log(newPosts);
Or, if you don't like .reduce(), you can do something very similar with the Map object and a for...of loop:
const posts = [
[
{
id: 2,
info: 'This is some information',
},
{
id: 3,
info: 'This is the other information',
},
],
[
{
id: 2,
info: 'This is a duplicated id I want to remove',
},
{
id: 4,
info: 'This information is safe',
},
],
];
const map = new Map();
for (const item of posts.flat()) {
if (map.has(item.id)) continue;
map.set(item.id, item);
}
const newPosts = Array.from(map.values());
console.log(newPosts);
Or even use a classic for loop to get the job done:
const posts = [
[
{
id: 2,
info: 'This is some information',
},
{
id: 3,
info: 'This is the other information',
},
],
[
{
id: 2,
info: 'This is a duplicated id I want to remove',
},
{
id: 4,
info: 'This information is safe',
},
],
];
const flattened = posts.flat();
const map = {};
for (let i = 0; i < flattened.length; i++) {
if (map[flattened[i].id]) continue;
map[flattened[i].id] = flattened[i];
}
console.log(Object.values(map));
Either way, in each of these examples we're following the same workflow:
Flatten the array so that all items are on the same level.
Filter out the items with the duplicate IDs.
I group by id in order to remove duplicates.
var posts = [[{id:2,info:"This is some information"},{id:3,info:"This is the other information"}],[{id:2,info:"This is a duplicated id I want to remove"},{id:4,info:"This information is safe"}]];
var agg = {}
posts.forEach(function(arr) {
arr.forEach(function(item) {
agg[item.id] = agg[item.id] || item
})
})
console.log(Object.values(agg))
.as-console-wrapper {
max-height: 100% !important
}
Flatten the array with flat, then use a set to keep track of the ids we already have. The ternary inside the filter is logic to check if the id is already in the set, and if it is, we filter the item out. Otherwise, we add the id back to the set.
const posts = [[{id:2,info:"This is some information"},{id:3,info:"This is the other information"}],[{id:2,info:"This is a duplicated id I want to remove"},{id:4,info:"This information is safe"}]];
const flat = posts.flat();
const ids = new Set();
const filtered = flat.filter((item) => ids.has(item.id) ? false : ids.add(item.id));
console.log(filtered);
.as-console-wrapper {
max-height: 100% !important
}
There are two things we need to do:
Flatten the inner areas into one main array with array.prototype.flat()
Remove duplicates based on, I'm assuming, the order of their appearance in the data.
We can do this by reducing the flattened array to an object with a condition that doesn't add any present id's if they're found
Then we convert that object to an array using Object.values()
let posts = [ [ { "id": 2, "info": "This is some information" }, { "id": 3, "info": "This is the other information" } ], [ { "id": 2, "info": "This is a duplicated id I want to remove" }, { "id": 4, "info": "This information is safe" } ] ]
let flattened = posts.flat()
console.log('Flattened: ', flattened)
let unique = flattened.reduce((acc, obj) => {
if (!acc[obj.id]) {
acc[obj.id] = obj
}
return acc
}, {})
console.log('Unique Objects: ', unique)
let result = Object.values(unique)
console.log('Final Array: ' ,result)
Doing it in one go and with a spread ... object merge:
let posts = [ [ { "id": 2, "info": "This is some information" }, { "id": 3, "info": "This is the other information" } ], [ { "id": 2, "info": "This is a duplicated id I want to remove" }, { "id": 4, "info": "This information is safe" } ] ]
let result = Object.values(
posts.flat().reduce((acc, obj) =>
({...{[obj.id]: obj}, ...acc})
, {})
);
console.log('Final Array: ', result);
I'm doing a search feature that user will input there option in filter object, then they will get the list they want.
So i have an array like this
let array = [
{
"id": 1,
"form_items": [
{
"value_text": "test",
"header_id": 1,
"value_number" 2000
},
{
"value_text": "test 2",
"header_id": 2,
"value_number" null
}
]
},
{
"id": 2,
"form_items": [
{
"value_text": "test 3",
"header_id": 3,
"value_number": 1000
}
]
}
]
and i have an object for filter like this
let filter = {
"value_text": "test 2",
"value_number": 2000
}
how can i return my array base on my filter object that element in form_items array match the condition ex: "test 2" in "header_id" : 2 and 2000 in "header_id" : 1
So my result will looks like this
[
{
"id": 1,
"form_items": [
{
"value_text": "test",
"header_id": 1,
"value_number" 2000
},
{
"value_text": "test 2",
"header_id": 2,
"value_number" null
}
]
}
]
You can do this with few loops, but It could be put into smaller functions.
var results = [];
for(const element of array){
// 1. Find all formItems that are matching your filter for each element
let matchingFormItems = []; // create an result array of formItems matching your filter criteria
for(const formItem of array['form_items']){ // iterate over all form_items
for(let filterKey: Object.keys(filter)){ // for each filter key, check if current formItem matches filter criteria
if(filter[filterKey] === formItem[filterKey]){ // if filter key is matching property from the formItem, push it to result Array
matchingFormItems.push(formItem);
break;// if one filter is matching, you can skip other
}
}
}
// 2. If at least one formItem has been found - push new object to the result array
if(matchingFormItems.length > 0 ){
results.push({ // it's best not to mutate input array, so we need to clone the object with only desired formItems.
'id': element.id,
'form_items': matchingFormItems
});
}
}
i have such an array.
[
{
id: 1,
title: "one",
cats: [],
},
{
id: 2,
title: "two",
cats: [{ id: 3 }, { id: 4 }],
},
{
id: 3,
title: "sub 1",
cats: [],
},
{
id: 4,
title: "sub 2",
cats: [],
},
];
How can i correctly reference the id 3 and 4 to the nested array of cats.
I need to achive the following.
I need to display the list as buttons, but the ones that have nested to be dropdown.
example
one.title
two.title
sub1.title
sub2.title
I dont want to have id 3 and 4 data like title, into the nested array because the router takes ID as param, so basically when i will click on sub1 it should display data from id-3.
Please help me understand this as i am new.
Thank you.
You can use this function to fomat your array:
const formatArray = arr =>
arr.map(item => {
if (item.cats.length === 0) {
return item;
} else {
const itemtFormatted = { ...item };
itemtFormatted.cats = item.cats.map(cat =>
arr.find(e => e.id === cat.id)
);
return itemtFormatted;
}
});
You can check here: https://jsfiddle.net/x9o6dkum/
I am trying to extract only the products in the array of objects with a product ID that exists in the masterAccessories list array which comes from a specific product that has a list of related_products in an array form.
JSON Example:
{"product":
{
"id": 3,
"product_name": "Product Name",
"sku": "sku_ID",
"description": "description",
"product_link": "link",
"cat_id": "cat-ID",
"cat_name": "Cat Name",
"related_products": [5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54]
}
},
{"product":
{
"id": 4,
"product_name": "product_name",
"sku": "sku_id",
"description": "description",
"product_link": "link",
"cat_id": "cat-tc",
"cat_name": "Cat Name",
"related_products": []
}
},
I am basically trying to find all the products with the id that exists in the related prodcuts array.
Related Products Array:
[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54]
My Attempt so far with no luck:
myPromise.then(function (result) {
let products = JSON.parse(result);
return products;
}, function (result) {
console.error(result);
}).then(function(products){
let productArray = products[0].products;
masterProduct += -1;
let accesoriesList = Object.values(productArray)[masterProduct];
let masterAccessories = accesoriesList.product.related_products;
console.log('Master: ',masterAccessories);
var newArray = [];
for(let i=0;i<productArray.length;i++){
if(masterAccessories.indexOf(productArray[i].product.id) === -1){
newArray.push(productArray[i]);
}
}
console.log('NewArray: ',newArray);
return accesoriesList;
})//just another then() that returns true
Here is one of the objects that gets returned from the productArray variable from console if it helps:
1:product:{id: 2, product_name: "Product Name", sku: "SkuID", description: "Description", product_link: "link", …} __proto__:Object
Any help would be greatly appreciated, thank you.
With jQuery:
var products = json;//<your product json array deserialized>;
var ids = [5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54];
var productsContainedArray = $.grep(products, function (prod) {
return ids.indexOf(prod.product.id) != -1;
});
I hope this meets your expectations for the desired result.
const
products = [
{
productId: 1,
name: 'A',
relatedProducts: [2]
},
{
productId: 2,
name: 'B',
relatedProducts: [1, 3]
},
{
productId: 3,
name: 'C',
relatedProducts: []
},
{
productId: 4,
name: 'D',
relatedProducts: [1]
}
];
function getReferencedProducts(input) {
let
referencedProducts = new Set();
// Iterate over all the products and create a set with the IDs of all
// referenced products. Each product ID will appear only once in the set.
input.forEach(product => {
// Create a new set based on the current set and the related products of
// the current product.
referencedProducts = new Set([...referencedProducts, ...product.relatedProducts]);
});
// Filter the products to only return those products whose ID is in
// the set of referenced products.
return input.filter(product => referencedProducts.has(product.productId));
}
// This should output products 1, 2, 3 as product is never referenced.
console.log(getReferencedProducts(products));
I just needed to say not equal to -1 instead of equal to 1.
Problem area:
for(let i=0;i<productArray.length;i++){
if(masterAccessories.indexOf(productArray[i].product.id) === -1){
newArray.push(productArray[i]);
}
console.log(productArray[i].product.id);
}
Answer:
for(let i=0;i<productArray.length;i++){
if(masterAccessories.indexOf(productArray[i].product.id) !== -1){
newArray.push(productArray[i]);
}
console.log(productArray[i].product.id);
}
See jsfiddle here: https://jsfiddle.net/remenyLx/2/
I have data that contains objects that each have an array of images. I want only the first image of each object.
var data1 = [
{
id: 1,
images: [
{ name: '1a' },
{ name: '1b' }
]
},
{
id: 2,
images: [
{ name: '2a' },
{ name: '2b' }
]
},
{
id: 3
},
{
id: 4,
images: []
}
];
var filtered = [];
var b = data1.forEach((element, index, array) => {
if(element.images && element.images.length)
filtered.push(element.images[0].name);
});
console.log(filtered);
The output needs to be flat:
['1a', '2a']
How can I make this prettier?
I'm not too familiar with JS map, reduce and filter and I think those would make my code more sensible; the forEach feels unnecessary.
First you can filter out elements without proper images property and then map it to new array:
const filtered = data1
.filter(e => e.images && e.images.length)
.map(e => e.images[0].name)
To do this in one loop you can use reduce function:
const filtered = data1.reduce((r, e) => {
if (e.images && e.images.length) {
r.push(e.images[0].name)
}
return r
}, [])
You can use reduce() to return this result.
var data1 = [{
id: 1,
images: [{
name: '1a'
}, {
name: '1b'
}]
}, {
id: 2,
images: [{
name: '2a'
}, {
name: '2b'
}]
}, {
id: 3
}, {
id: 4,
images: []
}];
var result = data1.reduce(function(r, e) {
if (e.hasOwnProperty('images') && e.images.length) r.push(e.images[0].name);
return r;
}, [])
console.log(result);
All answers are creating NEW arrays before projecting the final result : (filter and map creates a new array each) so basically it's creating twice.
Another approach is only to yield expected values :
Using iterator functions
function* foo(g)
{
for (let i = 0; i < g.length; i++)
{
if (g[i]['images'] && g[i]["images"].length)
yield g[i]['images'][0]["name"];
}
}
var iterator = foo(data1) ;
var result = iterator.next();
while (!result.done)
{
console.log(result.value)
result = iterator.next();
}
This will not create any additional array and only return the expected values !
However if you must return an array , rather than to do something with the actual values , then use other solutions suggested here.
https://jsfiddle.net/remenyLx/7/