Sort Object Elements in Javascript - javascript

I have an object like this:
{
"name":['John','Bob','Ram','Shyam'],
"marks":['64','22','80','32']
}
I have to sort the names. After I sort names, marks must be matched according to the names.
When I use sort() function, It only sorts the names. How can I sort my overall object?

One option is to alter your data structure to be more sortable. For example:
const data = {
names: ['John','Bob','Ram','Shyam'],
marks: ['64','22','80','32']
}
const people = data.names.map((name, i) => ({
name,
mark: data.marks[i]
}))
const sorted = people.sort((a, b) => a.name.localeCompare(b.name))
console.log(sorted)
A second option would be to keep an array of indexes, which you sort based on the data. This doesn't alter your original structures, but I don't think it is a good option, because it would be hard to keep both the names and marks arrays synced. For example:
const data = {
names: ['John','Bob','Ram','Shyam'],
marks: ['64','22','80','32']
}
const index = Array.from(Array(data.names.length).keys())
index.sort((a, b) => data.names[a].localeCompare(data.names[b]))
console.log(index)
// use the names & marks
index.forEach(i => {
console.log(`${data.names[i]} - ${data.marks[i]}`)
})

You can create another key by name rel and its value will be an array of objects , where each object has keys by name name & mark.
While creating this array you can use sort function to sort these objects in order
let obj = {
"name": ['John', 'Bob', 'Ram', 'Shyam'],
"marks": ['64', '22', '80', '32']
}
obj.rel = obj.name.map(function(e, i) {
return {
name: e,
mark: obj.marks[i]
}
}).sort((a, b) => a.name.localeCompare(b.name))
console.log(obj)

Related

ES6 way - Get unique values from a nested array by key

trying to improve my JS chops.
Is there a cleaner way to retrieve the property value from the array below, by key, from a nested object, removing duplicates and sorting them alphabetically?
Here's what I have:
getObjectValues(array, key){
var unique = [];
array.forEach(function(item){
item[key].forEach(function(value){
if (unique.indexOf(value) < 0) {
unique.push(value)
}
})
});
return unique.sort();
},
example array of object:
[
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']}
]
expected output should be an array:
var array = ['a','b','c']
You could just use a Set, and add all the items to it:
let arr = [
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']}
]
console.log(
Array.from(
new Set(
arr.reduce(
(carry, current) => [...carry, ...current.value],
[]
)
)
).sort()
)
If you need something concise, you may go as simple as that:
make use of Set to get rid of duplicates
employ Array.prototype.flatMap() (with slight touch of destructuring assignment) to extract value items from within all objects into single array
const src = [{name:'hello',value:['c','b','d']},{name:'hello',value:['e','b','c']},{name:'hello',value:['f','a','e']}],
result = [...new Set(src.flatMap(({value}) => value))].sort()
console.log(result)
.as-console-wrapper{min-height:100%;}
If you need something really fast, you may do the following:
use Array.prototype.reduce() to turn your array into Set of unique records (looping through value items with Array.prototype.forEach and doing Set.prototype.add())
spread resulting Set into array and .sort() that
const src = [{name:'hello',value:['c','b','d']},{name:'hello',value:['e','b','c']},{name:'hello',value:['f','a','e']}],
result = [...src.reduce((acc,{value}) =>
(value.forEach(acc.add, acc), acc), new Set())].sort()
console.log(result)
.as-console-wrapper{Min-height:100%;}

Filter array of objects based on the input passed: Javascript

I have an array of objects with the following structure
arr = [ { name: "abc" , items: ["itemA","itemB","itemC"], days :138} ,
{ name: "def" , items: ["itemA1","itemB2","itemC1"], days :157} ,
{ name: "hfg" , items: ["itemAN","itemB7","itemC7"], days :189} ]
This array needs to be filtered based on the search input passed. I was able to achieve the same for the name , where days is not getting filtered.
Also can someone help how to search across items array too so it filters the rows based on input passed
This is what I have tried
handleSearch = (arr, searchInput) => {
let filteredData= arr.filter(value => {
return (
value.name.toLowerCase().includes(searchInput.toLowerCase()) ||
value.days.toString().includes(searchInput.toString())
);
});
console.log(filteredData);
//this.setState({ list: filteredData });
}
You can use Array#some and then perform the same kind of match that you've already done :
The some() method tests whether at least one element in the array passes the test implemented by the provided function. It returns a Boolean value.
handleSearch = (arr, searchInput) => {
const filteredData = arr.filter(value => {
const searchStr = searchInput.toLowerCase();
const nameMatches = value.name.toLowerCase().includes(searchStr);
const daysMatches = value.days.toString().includes(searchStr);
const oneItemMatches = value.items.some(item => item.toLowerCase().includes(searchStr));
return nameMatches || daysMatches || oneItemMatches;
});
console.log(filteredData);
//this.setState({ list: filteredData });
}
As your search value can apply to all fields in your data array, you can combine the values together in one array (row by row) and perform the search in one place.
To do that, I've provided a snippet below that will filter the original array checking each object's values after the transformations. These involve using Object.values() to get the values of the object in an array, since this array is nested, we can make use of Array.flat() to flatten it into just the strings and numbers, finally call Array.some() to check if one of the values partially includes the search value (after they've both been lowercase-d).
const arr = [
{ name: "abc" , items: ["itemA","itemB","itemC"], days: 138 },
{ name: "def" , items: ["itemA1","itemB2","itemC1"], days: 157 },
{ name: "hfg" , items: ["itemAN","itemB7","itemC7"], days: 189 }
];
const handleSearch = (arr, searchInput) => (
arr.filter((obj) => (
Object.values(obj)
.flat()
.some((v) => (
`${v}`.toLowerCase().includes(`${searchInput}`.toLowerCase())
))
))
);
console.log('"A1" =>', JSON.stringify(handleSearch(arr, 'A1')));
console.log('189 =>', JSON.stringify(handleSearch(arr, 189)));
console.log('"nope" =>', JSON.stringify(handleSearch(arr, 'nope')));
NOTE: This approach has one obvious flaw, it will seach through numbers as strings, meaning that providing 89 as the search value will still return the second element.

Map an array of Javascript objects to sorted unique array by a specific attribute [duplicate]

This question already has answers here:
Converting string array to Name/Value object in javascript
(4 answers)
Closed 4 years ago.
How do I convert a string array:
var names = [
"Bob",
"Michael",
"Lanny"
];
into an object like this?
var names = [
{name:"Bob"},
{name:"Michael"},
{name:"Lanny"}
];
Super simple Array.prototype.map() job
names.map(name => ({ name }))
That is... map each entry (name) to an object with key "name" and value name.
var names = [
"Bob",
"Michael",
"Lanny"
];
console.info(names.map(name => ({ name })))
Silly me, I forgot the most important part
names.map(name => name === 'Bob' ? 'Saab' : name)
.map(name => ({ name }))
Use the Array.map() function to map the array to objects. The map() function will iterate through the array and return a new array holding the result of executing the function on each element in the original array. Eg:
names = names.map(function(ele){return {"name":ele}});
You can do this too:
var names = [
"Bob",
"Michael",
"Lanny"
];
var objNames = []
names.forEach(name => {
objNames.push({
name
})
})
Using ES6 you can set name and it is equal to name: name
you can use the map function.
In general, list.map(f) will produce a new list where each element at position i is the result of applying f to the element at the same position in the original list.
For example:
names.map(function(s) {
return {name: s}
});

Javascript string array to object [duplicate]

This question already has answers here:
Converting string array to Name/Value object in javascript
(4 answers)
Closed 4 years ago.
How do I convert a string array:
var names = [
"Bob",
"Michael",
"Lanny"
];
into an object like this?
var names = [
{name:"Bob"},
{name:"Michael"},
{name:"Lanny"}
];
Super simple Array.prototype.map() job
names.map(name => ({ name }))
That is... map each entry (name) to an object with key "name" and value name.
var names = [
"Bob",
"Michael",
"Lanny"
];
console.info(names.map(name => ({ name })))
Silly me, I forgot the most important part
names.map(name => name === 'Bob' ? 'Saab' : name)
.map(name => ({ name }))
Use the Array.map() function to map the array to objects. The map() function will iterate through the array and return a new array holding the result of executing the function on each element in the original array. Eg:
names = names.map(function(ele){return {"name":ele}});
You can do this too:
var names = [
"Bob",
"Michael",
"Lanny"
];
var objNames = []
names.forEach(name => {
objNames.push({
name
})
})
Using ES6 you can set name and it is equal to name: name
you can use the map function.
In general, list.map(f) will produce a new list where each element at position i is the result of applying f to the element at the same position in the original list.
For example:
names.map(function(s) {
return {name: s}
});

lodash sortBy then groupBy, is order maintained?

I'm having trouble figuring out from the lodash documentation if my assumption about sorting and grouping is correct.
If I use sortBy, then use groupBy, do the arrays produced by groupBy maintain the sort order of items?
For example, say I have the following array:
var testArray = [[5,6],[1,3],[5,4],[5,1]]
And I would like to group these by their first element, but also have them sorted by their second element within these groups. So, in lodash I assume I can do the following:
_.chain(testArray)
.sortBy(function (item) { return item[1]; })
.groupBy(function (item) { return item[0]; })
.value()
Which ends up producing what I would expect it to:
{
1: [[1,3]]
5: [[5,1],[5,4],[5,6]]
}
Is this just coincidence? Is there anything about how sortBy and groupBy work that ensures this ordering of the grouped arrays? The documentation says that sortBy is a stable sort, does that in the same way apply to groupBy? Is there any reason I should not assume this will work every time?
It's not. Here's example, where order is not retained:
const data = [
{
item: 'item1',
group: 'g2'
}, {
item: 'item2',
group: 'g3'
}, {
item: 'item3',
group: 'g1'
}, {
item: 'item4',
group: 'g2'
}, {
item: 'item5',
group: 'g3'
}
]
const groupedItems = _(data).groupBy(item => item.group).value()
In this case one would expect that group order would be: g2, g3, g1 - reality is that they are sorted g1, g2, g3.
You can re-sort them with original array though.
const groupedItems = _(data)
.groupBy(item => item.group)
.sortBy(group => data.indexOf(group[0]))
.value()
This will ensure original order of items.
The current implementation of _.groupBy is:
// An internal function used for aggregate "group by" operations.
var group = function(behavior) {
return function(obj, iteratee, context) {
var result = {};
iteratee = cb(iteratee, context);
_.each(obj, function(value, index) {
var key = iteratee(value, index, obj);
behavior(result, value, key);
});
return result;
};
};
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
_.groupBy = group(function(result, value, key) {
if (_.has(result, key)) result[key].push(value); else result[key] = [value];
});
Basically it iterates through each of the items in the collection in order (if the collection is array-like, which it would be after a sortBy), and pushes them to an array based on their key value.
So yes, I'm not sure if this is an "official" characteristic of _.groupBy, but it does preserve the order of array-like collections, and that's probably unlikely to change.
Function groupBy returns object. Object doesn't save property order.
Does JavaScript Guarantee Object Property Order?
But group arrays saves order, because thay are added with push function.

Categories

Resources