Get sub array based on array value - javascript

I have a categories array:
{id: 1, catName: "test", subCategories: Array(2)}
I need to retrieve the subCategories array based on the id of the category.
This return the entire category object, how can I change it to only return the subCategories array?
const subCategories = categoriesWithSub.filter(category => {
return category.id === departments.catId;
});

Destructure a find call:
const { subCategories } = categoriesWithSub.find(({ id }) => id === departments.catId);

Use Array#find to get the object and get the array using dot notation or bracket notation.
const subCategories = (categoriesWithSub.find(category => {
return category.id === departments.catId;
}) || {}).subCategories; // if find returns undefined then use an empty object to avoid error, alternately you can use if condition

You can use reduce.
const subCategories = categoriesWithSub.reduce((acc, category) => {
if (category.id === departments.catId) {
return acc.concat(category. subCategories)
}
return acc;
}, []);
Side note, reduce is a really powerful tool. find, map, forEach, filter are like shorthand versions of reduce for specific tasks.

Try this:
let categories = [ {id: 1, catName: "test", subCategories: ["test1","test2"]}, {id: 2, catName: "test", subCategories: Array(2)} ]
let departments = { catId: 1 }
const subCategories = categories.find(category => {
return category.id === departments.catId;
}).subCategories;
console.log( subCategories );

Try this
function getSubCategory() {
var categoriesWithSub = [{ id: 1, catName: "test", subCategories: ["test1","test2"] }, { id: 2, catName: "test", subCategories: ["test1","test2"] }]
var catId = 1;
for (var category = 0; category < categoriesWithSub.length; category++) {
if (categoriesWithSub[category].id == catId)
return categoriesWithSub[category].subCategories;
}
}

Related

Grouping array with map method

I want to group array of objects by its key,
The Original form;
data = [
{'id': 1, 'name': 'karthik'},
{'id': 1, 'age': 31},
{'id': 2, 'name': 'ramesh'},
{'id': 2, 'age': 22}
];
To transform in to,
groupedData = [
{'id': 1, 'name': 'karthik', 'age': 31},
{'id': 2, 'name': 'ramesh', 'age': 22}
];
What I tried,
this.data.map(item => item.id)
.filter((item, index, all) => all.indexOf(item) === index);
console.log(this.data);
Use reduce instead of map.
const groupedData = Object.values(this.data.reduce((a, { id, ...r }) => ({ ...a, [id]: { ...(a[id] || { id }), ...r }}), {}));
How this works:
Firstly, using reduce is far easier than any map solution because it allows us to have an accumulator value a.
Then, we extract the id, and the rest of the properties (because we don't know what they're called).
We return a, with the property keyed with the value of id being either the existing property or a new one with id, as well as the rest of the properties.
You can use reduce to create an object ( a table ) for each id.
const groupMap = data.reduce((group, currentData) => {
const id = currentData['id']
group[id] = { ...(group[id] || {}), ...currentData }
return group
} ,{})
what this returns is something like:
{
"1": {
"id": 1,
"name": "karthik",
"age": 31
},
"2": {
"id": 2,
"name": "ramesh",
"age": 22
}
}
group[id] = { ...(group[id] || {}), ...currentData } is basically "if you already saw this id, just merge the previous data with the current data"
then you can get the final result calling Object.values
const groupedData = Object.values(groupMap)
which just get the values of the object created above.
Try this
data = data.reduce((total, current, index) => {
for(let key in current) total[index][key] = current[key]
return total
}, [])
This function will help you)
function mergeobj(arrofobj) {
arrofobj.map((item, index) => {
for (let i = 0; i < arrofobj.length; i++) {
if(i==index)continue;
if (item['id'] == arrofobj[i]['id']) {
item = Object.assign(item, arrofobj[i]);
arrofobj.splice(i, 1);
--i;
}
}
return item;
})
return arrofobj; }

Is there any lodash method to update an object inside an array, where the item matched is going to have a new key?

Im adding a checkbox options and only have to update my object with a new key
so if I uncheck a item in a list i want to update the object
[ { id: 1 }, { id: 2 } ]
after unchecked:
[ { id: 1 }, { id: 2, unChecked: false } ]
any method to toggle this states?
thanks in advance
You can do it using native javascript and array map method. In the function check if the id matches then add the key there
let obj = [{
id: 1
}, {
id: 2
}]
function updateObj(obj, objId, key) {
return obj.map((item) => {
if (item.id === objId) {
return {
id: item.id,
[key]: false
}
} else {
return {
id: item.id
}
}
})
}
console.log(updateObj(obj, 2, 'unchecked'))
You can do this without lodash and using the .map method by adding the unChecked property if the id is not in the checked array by using .includes().
See working example below:
const checked = [2, 3], /* array holding all checked values */
arr = [{id: 1}, {id: 2}],
res = arr.map(({id}) => checked.includes(id) ? {id, unChecked: false} : {id});
console.log(res);

TypeScript - Take object out of array based on attribute value

My array looks like this:
array = [object {id: 1, value: "itemname"}, object {id: 2, value: "itemname"}, ...]
all my objects have the same attibutes, but with different values.
Is there an easy way I can use a WHERE statement for that array?
Take the object where object.id = var
or do I just need to loop over the entire array and check every item? My array has over a 100 entries, so I wanted to know if there was a more efficient way
Use Array.find:
let array = [
{ id: 1, value: "itemname" },
{ id: 2, value: "itemname" }
];
let item1 = array.find(i => i.id === 1);
Array.find at MDN: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/find
I'd use filter or reduce:
let array = [
{ id: 1, value: "itemname" },
{ id: 2, value: "itemname" }
];
let item1 = array.filter(item => item.id === 1)[0];
let item2 = array.reduce((prev, current) => prev || current.id === 1 ? current : null);
console.log(item1); // Object {id: 1, value: "itemname"}
console.log(item2); // Object {id: 1, value: "itemname"}
(code in playground)
If you care about iterating over the entire array then use some:
let item;
array.some(i => {
if (i.id === 1) {
item = i;
return true;
}
return false;
});
(code in playground)
You can search a certain value in array of objects using TypeScript dynamically if you need to search the value from all fields of the object without specifying column
var searchText = 'first';
let items = [
{ id: 1, name: "first", grade: "A" },
{ id: 2, name: "second", grade: "B" }
];
This below code will search for the value
var result = items.filter(item =>
Object.keys(item).some(k => item[k] != null &&
item[k].toString().toLowerCase()
.includes(searchText.toLowerCase()))
);
Same approach can be used to make a Search Filter Pipe in angularjs 4 using TypeScript
I had to declare the type to get it to work in typescript:
let someId = 1
array.find((i: { id: string; }) => i.id === someId)
You'll have to loop over the array, but if you make a hashmap to link each id to an index and save that, you only have to do it once, so you can reference any objeft after that directly:
var idReference = myArray.reduce(function( map, record, index ) {
map[ record.id ] = index;
return map;
}, {});
var objectWithId5 = myArray[ idReference["5"] ];
This does assume all ids are unique though.

How to add non duplicate objects in an array in javascript?

I want to add non-duplicate objects into a new array.
var array = [
{
id: 1,
label: 'one'
},
{
id: 1,
label: 'one'
},
{
id: 2,
label: 'two'
}
];
var uniqueProducts = array.filter(function(elem, i, array) {
return array.indexOf(elem) === i;
});
console.log('uniqueProducts', uniqueProducts);
// output: [object, object, object]
live code
I like the class based approach using es6. The example uses lodash's _.isEqual method to determine equality of objects.
var array = [{
id: 1,
label: 'one'
}, {
id: 1,
label: 'one'
}, {
id: 2,
label: 'two'
}];
class UniqueArray extends Array {
constructor(array) {
super();
array.forEach(a => {
if (! this.find(v => _.isEqual(v, a))) this.push(a);
});
}
}
var unique = new UniqueArray(array);
console.log(unique);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
Usually, you use an object to keep track of your unique keys. Then, you convert the object to an array of all property values.
It's best to include a unique id-like property that you can use as an identifier. If you don't have one, you need to generate it yourself using JSON.stringify or a custom method. Stringifying your object will have a downside: the order of the keys does not have to be consistent.
You could create an objectsAreEqual method with support for deep comparison, but this will slow your function down immensely.
In two steps:
var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];
// Create a string representation of your object
function getHash(obj) {
return Object.keys(obj)
.sort() // Keys don't have to be sorted, do it manually here
.map(function(k) {
return k + "_" + obj[k]; // Prefix key name so {a: 1} != {b: 1}
})
.join("_"); // separate key-value-pairs by a _
}
function getHashBetterSolution(obj) {
return obj.id; // Include unique ID in object and use that
};
// When using `getHashBetterSolution`:
// { '1': { id: '1', label: 'one' }, '2': /*etc.*/ }
var uniquesObj = array.reduce(function(res, cur) {
res[getHash(cur)] = cur;
return res;
}, {});
// Convert back to array by looping over all keys
var uniquesArr = Object.keys(uniquesObj).map(function(k) {
return uniquesObj[k];
});
console.log(uniquesArr);
// To show the hashes
console.log(uniquesObj);
You can use Object.keys() and map() to create key for each object and filter to remove duplicates.
var array = [{
id: 1,
label: 'one'
}, {
id: 1,
label: 'one'
}, {
id: 2,
label: 'two'
}];
var result = array.filter(function(e) {
var key = Object.keys(e).map(k => e[k]).join('|');
if (!this[key]) {
this[key] = true;
return true;
}
}, {});
console.log(result)
You could use a hash table and store the found id.
var array = [{ id: 1, label: 'one' }, { id: 1, label: 'one' }, { id: 2, label: 'two' }],
uniqueProducts = array.filter(function(elem) {
return !this[elem.id] && (this[elem.id] = true);
}, Object.create(null));
console.log('uniqueProducts', uniqueProducts);
Check with all properties
var array = [{ id: 1, label: 'one' }, { id: 1, label: 'one' }, { id: 2, label: 'two' }],
keys = Object.keys(array[0]), // get the keys first in a fixed order
uniqueProducts = array.filter(function(a) {
var key = keys.map(function (k) { return a[k]; }).join('|');
return !this[key] && (this[key] = true);
}, Object.create(null));
console.log('uniqueProducts', uniqueProducts);
You can use reduce to extract out the unique array and the unique ids like this:
var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];
var result = array.reduce(function(prev, curr) {
if(prev.ids.indexOf(curr.id) === -1) {
prev.array.push(curr);
prev.ids.push(curr.id);
}
return prev;
}, {array: [], ids: []});
console.log(result);
.as-console-wrapper{top:0;max-height:100%!important;}
If you don't know the keys, you can do this - create a unique key that would help you identify duplicates - so I did this:
concat the list of keys and values of the objects
Now sort them for the unique key like 1|id|label|one
This handles situations when the object properties are not in order:
var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];
var result = array.reduce(function(prev, curr) {
var tracker = Object.keys(curr).concat(Object.keys(curr).map(key => curr[key])).sort().join('|');
if(!prev.tracker[tracker]) {
prev.array.push(curr);
prev.tracker[tracker] = true;
}
return prev;
}, {array: [], tracker: {}});
console.log(result);
.as-console-wrapper{top:0;max-height:100%!important;}

How can I get a unique array based on object property using underscore

I have an array of objects and I want to get a new array from it that is unique based only on a single property, is there a simple way to achieve this?
Eg.
[ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ]
Would result in 2 objects with name = bill removed once.
Use the uniq function
var destArray = _.uniq(sourceArray, function(x){
return x.name;
});
or single-line version
var destArray = _.uniq(sourceArray, x => x.name);
From the docs:
Produces a duplicate-free version of the array, using === to test object equality. If you know in advance that the array is sorted, passing true for isSorted will run a much faster algorithm. If you want to compute unique items based on a transformation, pass an iterator function.
In the above example, the function uses the objects name in order to determine uniqueness.
If you prefer to do things yourself without Lodash, and without getting verbose, try this uniq filter with optional uniq by property:
const uniqFilterAccordingToProp = function (prop) {
if (prop)
return (ele, i, arr) => arr.map(ele => ele[prop]).indexOf(ele[prop]) === i
else
return (ele, i, arr) => arr.indexOf(ele) === i
}
Then, use it like this:
const obj = [ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ]
obj.filter(uniqFilterAccordingToProp('abc'))
Or for plain arrays, just omit the parameter, while remembering to invoke:
[1,1,2].filter(uniqFilterAccordingToProp())
If you want to check all the properties then
lodash 4 comes with _.uniqWith(sourceArray, _.isEqual)
A better and quick approach
var table = [
{
a:1,
b:2
},
{
a:2,
b:3
},
{
a:1,
b:4
}
];
let result = [...new Set(table.map(item => item.a))];
document.write(JSON.stringify(result));
Found here
You can use the _.uniqBy function
var array = [ { id: 1, name: 'bob' }, { id: 2, name: 'bill' }, { id: 1, name: 'bill' },{ id: 2, name: 'bill' } ];
var filteredArray = _.uniqBy(array,function(x){ return x.id && x.name;});
console.log(filteredArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>
In the above example, filtering is based on the uniqueness of combination of properties id & name.
if you have multiple properties for an object.
then to find unique array of objects based on specific properties, you could follow this method of combining properties inside _.uniqBy() method.
I was looking for a solution which didn't require a library, and put this together, so I thought I'd add it here. It may not be ideal, or working in all situations, but it's doing what I require, so could potentially help someone else:
const uniqueBy = (items, reducer, dupeCheck = [], currentResults = []) => {
if (!items || items.length === 0) return currentResults;
const thisValue = reducer(items[0]);
const resultsToPass = dupeCheck.indexOf(thisValue) === -1 ?
[...currentResults, items[0]] : currentResults;
return uniqueBy(
items.slice(1),
reducer,
[...dupeCheck, thisValue],
resultsToPass,
);
}
const testData = [
{text: 'hello', image: 'yes'},
{text: 'he'},
{text: 'hello'},
{text: 'hell'},
{text: 'hello'},
{text: 'hellop'},
];
const results = uniqueBy(
testData,
item => {
return item.text
},
)
console.dir(results)
In case you need pure JavaScript solution:
var uniqueProperties = {};
var notUniqueArray = [ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ];
for(var object in notUniqueArray){
uniqueProperties[notUniqueArray[object]['name']] = notUniqueArray[object]['id'];
}
var uniqiueArray = [];
for(var uniqueName in uniqueProperties){
uniqiueArray.push(
{id:uniqueProperties[uniqueName],name:uniqueName});
}
//uniqiueArray
unique array by id property with ES6:
arr.filter((a, i) => arr.findIndex(b => b.id === a.id) === i); // unique by id
replace b.id === a.id with the relevant comparison for your case

Categories

Resources