Tips for sorting an array of objects by multiple keys while maintaining the order of each key that comes before

I am looking to create a versatile function that can organize an array of objects based on specified keys, while maintaining the order of previous keys. Here is a sample scenario:

const input = [
  { a: 'aardvark', b: 'bear', c: 'camel', d: 1 },
  { a: 'anemone', b: 'bat', c: 'cobra', d: 6 },
  { a: 'aardvark', b: 'badger', c: 'camel', d: 2 },
  { a: 'alligator', b: 'bat', c: 'chicken', d: 2 },
  { a: 'alligator', b: 'beetle', c: 'cow', d: 1 },
  { a: 'alligator', b: 'bat', c: 'crab', d: 3 },
]

sortFunction(['a', 'b', 'd'], input)

// output
[
  { a: 'aardvark', b: 'badger', c: 'camel', d: 2 },
  { a: 'aardvark', b: 'bear', c: 'camel', d: 1 },
  { a: 'alligator', b: 'bat', c: 'chicken', d: 2 },
  { a: 'alligator', b: 'bat', c: 'crab', d: 3 },
  { a: 'alligator', b: 'beetle', c: 'cow', d: 1 },
  { a: 'anemone', b: 'bat', c: 'cobra', d: 6 },
]

The initial sorting key is a, so the output correctly arranges the data by a in descending order. The subsequent key in the list is b, which then reorders items with matching values of a based on the b keys. Finally, d is used to reorder items with identical values of a and b. For example, if there are two items with a: alligator and b: bat, the item with d: 2 is positioned before the one with d: 3.

The challenge lies in transforming this specific example into a generic function capable of accepting any array of objects and organizing them according to a defined list of keys, where the values of those keys are either strings or numbers.

Answer №1

To sort your input data, one effective method is to utilize the `sort()` function along with a comparator callback that iterates through each key until it establishes the correct sorting order:

function customSort<K extends PropertyKey, T extends Record<K, string | number>>(
  keys: K[], objects: T[]
) {
  objects.sort((a, b) => {
    for (const key of keys) {
      if (a[key] < b[key]) return -1;
      if (a[key] > b[key]) return 1;
    }
    return 0;
  })
}

This function is designed as a generic one, where the `objects` parameter enforces that the array of objects contains values of type `string` or `number` at the specified keys in the `keys` array.

You can test this functionality on your sample input using the code snippet below:

customSort(['a', 'b', 'd'], inputData);

console.log(inputData.map(value => JSON.stringify(value)).join("\n"));    
/*
"{"a":"aardvark","b":"badger","c":"camel","d":2}
{"a":"aardvark","b":"bear","c":"camel","d":1}
{"a":"alligator","b":"bat","c":"chicken","d":2}
{"a":"alligator","b":"bat","c":"crab","d":3}
{"a":"alligator","b":"beetle","c":"cow","d":1}
{"a":"anemone","b":"bat","c":"cobra","d":6}" ]
*/

You can also experiment with the code using this Playground link provided.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a custom type for the parameter of an arrow function in Typescript

I need assistance defining the type for an object parameter in an arrow function in TypeScript. I am new to TypeScript and have not been able to find any examples illustrating this scenario. Here is my code: const audioElem = Array.from(videoElem.pare ...

Encountered a problem while attempting to post in Angular, receiving an error message stating "net::ERR

I recently started learning Nodejs. I've created an API on a local server using Mysql and I'm working on the frontend with Angular, while using Nodejs and Express as the backend. However, I'm facing an issue where my Angular app cannot conne ...

What about a toggle for read-only TypeScript everywhere? (parameters in functions)

Is there a method, whether through a macro library, an eslint rule, a tsconfig setting, a special global.d.ts file, or some other means, to automatically set function arguments as readonly by default? // I wish for the compiler to transform this: functio ...

How do I retype an interface from a dependency?

It's difficult to put into words, so I have created a repository for reference: https://github.com/galenyuan/how-to-retyping My goal is to achieve the following: import Vue from 'vue' declare module 'vuex/types/vue' { interfac ...

Using an aria-label attribute on an <option> tag within a dropdown menu may result in a DAP violation

Currently, I am conducting accessibility testing for an Angular project at my workplace. Our team relies on the JAWS screen reader and a helpful plugin that detects UI issues and highlights them as violations. Unfortunately, I've come across an issue ...

What is preventing type guarding in this particular instance for TypeScript?

Here is an example of some code I'm working on: type DataType = { name: string, age: number, } | { xy: [number, number] } function processInput(input: DataType) { if (input.name && input.age) { // Do something } e ...

Angular integration problem with aws-amplify when signing up with Google account

I am attempting to integrate AWS-Amplify(^4.3.0) with angular-12 and typescript (4.3.5). I have followed the documentation to configure amplify properly, but when trying to start the app, I encountered some amplify errors as shown below. Warning: D:\G ...

Will the component re-render before executing the next lines when using setState or dispatch with the useReducer hook?

Upon using the useState and useReducer hooks, I encountered an issue where any code lines following the state update function (setState, dispatch) would be executed in the subsequent re-rendering, with the previous state intact before the update. Essential ...

Advantages of optimizing NodeJS/TypeScript application by bundling it with webpack

Currently, I am working on a Node/Express application and I am interested in incorporating the most recent technologies. This includes using TypeScript with node/Express along with webpack. I have a question: What advantages come with utilizing webpack t ...

Managing Visual Studio Code Extension Intellisense: A Guide

I am looking to create an extension I recommend using "CompletionList" for users. Users can trigger completion by running "editor.action.triggerSuggest" The process of my extensions is as follows: Users input text If they press the "completion command," ...

Using TypeScript to Verify the Existence of Words in a String

Is there a way in typescript to find specific words within a given string? For example: If we have a list: ['Mr', 'Mrs', 'FM.', 'Sir'] and a string named 'Sir FM. Sam Manekshaw'. The words 'Sir' ...

Exploring the concept of recursive method calls in TypeScript

I am trying to call the filterArr method inside the filterArr itself. Here is my current implementation: function filterArr(array, search) { var result = []; array.forEach((a)=> { var temp = [], o = {}, ...

Why is it that in reactive forms of Angular, the parameter being passed in formControlName is passed as a string?

I am currently working on a reactive form in Angular. In order to synchronize the FormControl object from the TypeScript file with the form control in the HTML file, you need to utilize the formControlName directive. This is accomplished as shown below: f ...

Steps to resolve the error message 'Argument of type 'number' is not assignable to parameter of type 'string | RegExp':

Is there a way to prevent users from using special symbols or having blank spaces without any characters in my form? I encountered an error when trying to implement this in my FormGroup Validator, which displayed the message 'Argument of type 'nu ...

Having trouble invoking the "done" function in JQuery following a POST request

I am currently working on a Typescript project that utilizes JQuery, specifically for uploading a form with a file using the JQuery Form Plugin. However, after the upload process, there seems to be an issue when trying to call the "done" function from JQue ...

Unveiling RxJs: The secret to extracting the notifier value using the takeuntil operator

I have a straightforward Rxjs timer set up that runs until a notifier emits a signal, it's pretty basic so far. enum TimerResult = { COMPLETE, ABORTED, SKIPPED }; _notifier: Subject<TimerResult> = new Subject(); notifier$: Observab ...

combine string inputs when ng-click is triggered

Is there a way to pass a concatenated string using ng-click to MyFunction(param: string)? I have tried but so far, no luck: <input id="MeasurementValue_{{sample.Number}}_{{$index}}" ng-click="Vm.MyFunction('MeasurementValue_{{sample.Number ...

Creating a unique user interface for VSCode extension

Recently, I've delved into the world of developing extensions for Visual Studio. Unfortunately, my expertise in TypeScript and Visual Studio Code is quite limited. My goal is to create an extension that mirrors the functionality of activate-power-mod ...

Tips for obtaining type narrowing for a function within a mixed array

In my coding adventure, I have crafted a brilliant match function. This function is designed to take a value along with an array of [case, func] pairs. The value is then compared to each case, and if a match is found, the associated func is executed with t ...

Leveraging CSS attribute selectors within JSX using TypeScript

With pure HTML/CSS, I can achieve the following: <div color="red"> red </div> <div color="yellow"> yellow </div> div[color="red"] { color: red; } div[color="yellow"] { color: yellow; ...