How To Sort An Array Of Complex Objects?
Solution 1:
There are multiple ways to implement this based on your overall system so for my suggestion, I am going to assume the following:
- You want to keep the data as is for performance or some other reasons (i.e. flattening the object through some kind of "normalizer" is not an option).
- The key cannot be an object, but has to be a string
- Either you or the user can set the key.
- There exists a character or a set of characters that can be used in a key string as a delimiter to construct a tree of keys (e.g. a dot in
'info.price'
, or an arrow in'info->price'
). An important property of the delimiter is that it is not valid to use it in a flat key (i.e. in the last example something likedata = [{ 'info->price': '$50' }]
is not allowed)
Ok now you just need to implement an accessor to use the complex keys on your object, something similar to Lodash.get. A simple implementation would be something like:
constDELIMITER = '->';
functionget(obj, key) {
if (!obj) {
// in case of null or undefinedreturn obj;
}
if (!key) {
// empty string or something like thatreturn obj;
}
if (key.includes(DELIMITER)) {
const keyComponents = key.split(DELIMITER);
const firstKeyComponent = keyComponents.shift();
const newKey = keyComponents.join(DELIMITER);
returnget(obj[firstKeyComponent], newKey)
}
return obj[key];
}
Emphasis on the simple here, because recalculating keyComponents
every time is not ideal. You also might want add extra if cases for how to handle strings or arrays, those could cause problems if a key component is a number.
EDIT: Also maybe use Object.prototype.hasOwnProperty
to check if a key is identical to a built in Object function, or better yet check if obj is a function and decide how to handle that scenario.
After you have this you can just replace that compare segment of your code with this:
sortableItems.sort((a: any, b: any) => {
const aValue = get(a, sortConfig.key);
const bValue = get(b, sortConfig.key);
if (aValue < bValue) {
return sortConfig.direction === 'ascending' ? -1 : 1;
}
if (aValue] > bValue) {
return sortConfig.direction === 'ascending' ? 1 : -1;
}
return0;
});
And you're good to go for most cases. I don't know how "wild" your data can get so make sure to test a bunch of scenarios.
Solution 2:
The problem you are running into is deep cloning of an object. the spread operator only goes 1 level deep and you are trying to go two. You can use libraries from lodash or other deep cloning. I use the JSON trick.
const [data, setData] = useState(initData);
functionnewArray() {
returnJSON.parse(JSON.stringify(data));
}
Example shows sorting with two levels: https://codesandbox.io/s/serverless-sea-jt220?file=/src/App.js
Post a Comment for "How To Sort An Array Of Complex Objects?"