Utilize GroupBy and tally up items within an array using typescript

Here is a representation of my array, which is not a type of string but its own object called MyObject (similar to setter and getter objects in Java)

["Car","model","year","color","price"]
["Table","model","year","color","price"]
["Car","model","year","color","price"]
["Car","model","year","color","price"]
["Laptop","model","year","color","price"]
["Laptop","model","year","color","price"]

I am looking to group this data in TypeScript and count the occurrences of each item in the array (similar to how it's done in SQL)

name  |count
 Car  | 3
Laptop| 2
Table | 1

In my TypeScript file, I have the following code:

private groupByObjects() {
  //this reads all data in the 'allData[]' array from the service
  this.dataService.retrieveData().subscribe(allData => {

});

}

Can anyone assist me in writing this logic in TypeScript?

Answer №1

After numerous attempts, I was finally able to come up with a solution that works perfectly for me. I am sharing it now in the hopes that it will be helpful to anyone facing a similar issue.

function groupByElement(receivedData: ReceivedData, elements: Array<GroupByElement>) {
    let groupElement: GroupByElement = new GroupByElement;

    if (!elements.find(x => x.element== receivedData.element)) {
      groupElement.element= receivedData.element;
      groupElement.count = 1;
      elements.push(groupElement);
    } else {
      this.updateElementCounter = elements.find(x => x.element== receivedData.element)?.count;
      this.updateElementCounter! += 1;
      this.indexElementCount = elements.findIndex(x => x.element== receivedData.element);

      elements[this.indexElementCount].count = this.updateElementCounter!;
    }
  }

Answer №2

Why not give lodash a try?

You can achieve this functionality with just 2 simple lines of code:

private groupByObjects() {
  // This method retrieves data from the service and processes it
  this.dataService.retrieveData().subscribe(allData => {
    const counts = _.countBy(allData, '[0]');
    const data = _.unionBy(allData, '[0]');
    console.log(counts, data);
  });

Don't forget to install and import lodash:

npm install -s lodash

import * as _ from 'lodash';

Answer №3

I really appreciate the concept of a list reducer that utilizes a function returning another function. This allows for flexibility in specifying which key to use, as demonstrated with the key being set to 0 in this case.

interface PropObject {
  [index: string]: number;
}

const groupByCounter = (key : number) => (result : PropObject ,current : string []) => {

  result[current[key]] = result[current[key]] ? result[current[key]] + 1 : 1;
  return result;
};

const data : string [][] = [["Car","model","year","color","price"],
["Table","model","year","color","price"],
["Car","model","year","color","price"],
["Car","model","year","color","price"],
["Laptop","model","year","color","price"],
["Laptop","model","year","color","price"]];

const group = data.reduce(groupByCounter(0),{});
console.log(group);

Link to typescript playground.

Check out the javascript version

Answer №4

You have the ability to achieve this with a time complexity of O(n) using a straightforward reduction

In your specific scenario,

type ApplyFunction<X, T, R> = (all: X, current: T) => R
type GetFunction<T,R> = (t: T) => R

const groupAndApplyByIndex = <T, V extends string | number, R>(data: Array<T>, get: GetFunction<T,V>, apply: ApplyFunction<Record<V, R>, V, R>) => {
  return data.reduce((all, element) => {
    return {
      ...all,
      [get(element)]: apply(all, get(element))
    }
  }, {} as Record<V, R>)
}

You can utilize the above function in your code by simply

private groupByObjects() {
  //this read all data in array allData[] from service
  this.dataService.retrieveData().subscribe(allData => {

    const getX: GetFunction<string[], string> = (t) => t[0]
    const counts = groupAndApplyByIndex(allData, getX, (all, element) => ((all[element] as number || 0) + 1))

    // Implement the rest of your logic here...
  });

Through the use of the method outlined above, you possess a function that is capable of performing tasks such as counting or executing other transformations specified within the apply function

TypeScript Playground

Answer №5

If you're already utilizing rxjs, my suggestion is to stick with it. While I can't guarantee this is the optimal solution and recommend debugging, I personally find this approach enjoyable.

type Item = [string, string, string, string, string]; // consider refining this type definition
type ItemCount = [string, number];

const source$: Observable<Item[]> = of([
  ["Car","model","year","color","price"],
  ["Table","model","year","color","price"],
  ["Car","model","year","color","price"],
  ["Car","model","year","color","price"],
  ["Laptop","model","year","color","price"],
  ["Laptop","model","year","color","price"]
]); // mock data obtained from this.dataService.retrieveData()

source$.pipe(
  mergeMap(res => from(res)), // emit each item individually
  groupBy((item: Item) => item[0]),
  mergeMap((item$: GroupedObservable<Item>) => item$.pipe( 
    count(), // wait for completion, then emit count
    map<number, ItemCount>(c => [item$.key, c]) // convert count into a tuple of [key, count]
  )),
  toArray(), // Wait until all items have been processed, then emit the final ItemCount[]
  map((itemCounts: ItemCount[]) => new Map<string, number>(itemCounts)) // alternatively, use Object.fromEntries(itemCounts)
).subscribe(mapOfCountsPerKey => {
    // implement your desired logic here
});

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

Having trouble displaying nested routes in Angular within the view

I'm encountering some issues with child/nested routes in Angular 4. In the app.module.ts file, my imports statement looks like this: RouterModule.forRoot([ { path: 'templates', component: TemplateLandingC ...

Array of dynamically typed objects in Typescript

Hello, I am a newbie to Typescript and I recently encountered an issue that has left me stumped. The problem I am facing involves feeding data to a Dygraph chart which requires data in the format [Date, number, number,...]. However, the API I am using prov ...

Newbie seeking help with Angular Services

I'm struggling to avoid duplicating code by using a service. How can I refactor this into a service and then utilize it in the component? Any assistance would be greatly appreciated. function navigateToLink(myRecords) { this.targetLink = this.data.l ...

The value from select2 dropdown does not get populated in my article in Angular

I am attempting to link the selected value in a dropdown menu to an article, with a property that matches the type of the dropdown's data source. However, despite logging my article object, the property intended to hold the selected dropdown value app ...

The type '[Images]' cannot be assigned to type 'string'

I am attempting to pass an array of objects through props, but encountered the following error: (property) images: [Images] Type '[Images]' is not assignable to type 'string'.ts(2322) ProductBlock.tsx(4, 5): The expected type co ...

I'm looking to learn how to implement the delete method in an API using TypeScript. Can anyone help me out

I am seeking guidance on utilizing 'axios' within 'nuxt.js'. I have experimented with sample data, and I am particularly interested in learning how to utilize the 'axios' method within 'nuxt.js' using TypeScript. T ...

Leverage a variety of environment files

In my Angular 7 project, I am working with the environment.prod.ts file that looks like this: export const environment = { production: true, apiBaseUri: 'https://api.xyz.com' }; Now, I am facing the task of deploying this application on two ...

Jest's --findRelatedTests fails to identify associated test cases

Whenever I execute the command jest --bail --findRelatedTests src/components/BannerSet/BannerSet.tsx , an unexpected message is displayed: I couldn't locate any tests and hence exiting with code 1 If you want to exit with code 0 even when there are n ...

Steps for sorting items from a list within the past 12 hours

I'm currently working with Angular and I have data in JSON format. My goal is to filter out items from the last 12 hours based on the "LastSeen" field of the data starting from the current date and time. This is a snippet of my data: { "Prod ...

What is the proper way to arrange dates within strings in Angular?

I'm currently facing an issue with sorting two strings. The strings in question are: "2022 | Dec (V2 2022)" "2022 | Jul (V1 2022)" Although I am attempting to sort them using localeCompare, it is not yielding the correct result. T ...

Discovering React Styled Components Within the DOM

While working on a project using Styled Components in React, I have successfully created a component as shown below: export const Screen = styled.div({ display: "flex", }); When implementing this component in my render code, it looks like this ...

An Unexpected Error Occurred While Importing HttpClientModule in Angular's Tour of Heroes

Currently, I am working through the Angular tutorial for beginners. You can find the tutorial here. Following the instructions to import the HttpClientModule, I encountered the error message below. I need assistance with this issue. I am running npm on a ...

The resolve.alias feature in webpack is not working properly for third-party modules

Currently, I am facing an issue trying to integrate npm's ng2-prism with angular2-seed. The problem arises when importing angular2/http, which has recently been moved under @angular. Even though I expected webpack's configuration aliases to hand ...

What could be causing the Typescript error when utilizing useContext in combination with React?

I am currently working on creating a Context using useContext with TypeScript. I have encapsulated a function in a separate file named MovieDetailProvider.tsx and included it as a wrapper in my App.tsx file. import { Context, MovieObject } from '../in ...

List out the decorators

One query is bothering me - I am attempting to create my own version of Injectable and I need to determine if a specific decorator exists in my Class. Is there a way to list all decorators of a class? Let's take the example below. All I want to know i ...

Select specific columns from an array using Typescript

I have a collection of objects and I'm looking for a way to empower the user to choose which attributes they want to import into the database. Is there a method to map and generate a separate array containing only the selected properties for insertion ...

Automatically select the unique item from the list with Angular Material AutoComplete

Our list of document numbers is completely unique, with no duplicates included. I am attempting to implement a feature in Angular Material that automatically selects the unique entry when it is copied and pasted. https://i.stack.imgur.com/70thi.png Curr ...

Typedoc does not create documentation for modules that are imported

Whenever I generate documentation with TypeDoc, I am encountering an issue where imported files come up empty. If I add a class to the file specified in entryPoints, I get documentation for that specific class. However, the imported files show no document ...

Guide on obtaining the total value from a JSON Array in Angular 2 using TypeScript

I received a JSON response which includes carts values with different amounts. "carts": { "value": [ { "Amt": 40 }, { "Amt": 20.25 }, ...

Enhancing keyboard accessibility with the spacebar for radio buttons and check boxes in Angular 2

I am currently working on a form in Angular 2 that includes radio buttons and checkboxes. When tabbing through the fields, they are highlighted properly. However, I am facing an issue with the radio buttons - I want them to be selected when I hit the space ...