Ways to add items to an array adjacent to items sharing a common property value

I have an array consisting of various objects

const allRecords = [
  {
    type: 'fruit',
    name: 'apple'
  },
  {
    type: 'vegetable',
    name: 'celery'
  },
  {
    type: 'meat',
    name: 'chicken'
  }
]

My goal is to merge objects from another array next to similar type elements.

const newRecords = [
  {
    type: 'fruit',
    name: 'pear'
  },
  {
    type: 'vegetable',
    name: 'spinach'
  },
  {
    type: 'meat',
    name: 'pork'
  }
]

For instance, calling this function:

allRecords.sortAndInsert(newRecords)

Should yield a result as follows:

[
  {
    type: 'fruit',
    name: 'apple'
  },
  {
    type: 'fruit',
    name: 'pear'
  },
  {
    type: 'vegetable',
    name: 'celery'
  },
  {
    type: 'vegetable',
    name: 'spinach'
  },
  {
    type: 'meat',
    name: 'chicken'
  },
  {
    type: 'meat',
    name: 'pork'
  },

With my current code, I determine the position by calculating the length of arrays:

// Calculate record amount per group. 
//In our example, it will be 2 for each group - 'apple' and 'pear', etc.
const multiplier = (allRecords.length + newRecords.length) / 
   (newRecords.length);
for (let i = 0; i < newRecords.length; i++){
    // Insert record at 1 + i + multiplier. 'pear' should go to 1 with 0 * 2 = 1
    allRecords.splice(1 + i * multiplier, 0, newRecords[i]);
  }
return allRecords;

However, this method lacks readability and assumes each group has only one item of each type.

My ideal solution would group items based on properties and sort them accordingly in a specific order (e.g., 'fruit' first, followed by 'vegetable' then 'meat').

Answer №1

Utilizing maps would be the perfect solution for that scenario. Here's a practical example of how it could work:

let foodMap = new Map();

foodMap.set('fruit', [{
  name: 'banana',
  type: 'fruit'
}]);
foodMap.set('vegetable', [{
  name: 'carrot',
  type: 'vegetable'
}]);
foodMap.set('meat', [{
  name: 'beef',
  type: 'meat'
}]);

const additionalRecords = [{
  type: 'fruit',
  name: 'orange'
}, {
  type: 'vegetable',
  name: 'broccoli'
}, {
  type: 'meat',
  name: 'turkey'
}]

additionalRecords.forEach(function(record) {
  let array = foodMap.get(record.type);
  array.push(record);
  foodMap.set(record.type, array);
});

for (let [key, value] of foodMap) {
  console.log(key);
  console.log(value);
}

Answer №2

Grouping

In this explanation, we will cover the process of efficiently grouping similar items using a Map in JavaScript. We start by defining two arrays, allRecords and newRecords, without any specific order.

We begin by grouping the items in allRecords based on the type property:

// Grouping allRecords
const allRecords =
  [ { type: 'fruit', name: 'apple' }
  , { type: 'vegetable', name: 'spinach' }
  , { type: 'meat', name: 'chicken' }
  , { type: 'fruit', name: 'raspberry' } // added item
  ]

const groupAll = groupBy(x => x.type, allRecords)

console.log(groupAll)
// Output shown as Map with grouped items

Next, we do the same for the newRecords array:

// Grouping newRecords
const newRecords =
  [ { type: 'meat', name: 'pork' }
  , { type: 'fruit', name: 'pear' }
  , { type: 'vegetable', name: 'celery' }
  , { type: 'dairy', name: 'milk' } // added item
  ]

const groupNew = groupBy(x => x.type, newRecords)

console.log(groupNew)
// Output shown as Map with grouped items

After grouping, we merge these two maps to combine and organize all items together:

// Merging both groups
const mergedGroups = mergeMap(groupAll, groupNew)

console.log(mergedGroups)
// Output shown as Map with combined and organized items

Once all items are organized, we can extract the values and sort them based on different criteria:

// Extracting values for sorting
const unsortedValues = [].concat(...mergedGroups.values())

console.log(unsortedValues)
// Output shown as an array of unsorted values

Sorting

Now, let's delve into sorting these values based on certain parameters. We have defined functions like orderByName and orderByTypes to support custom sorting:

// Sorting by name
const sortedByName = unsortedValues.sort(orderByName)

console.log(sortedByName)
// Output shown as sorted values by name
// Sorting by types
const sortedByType = unsortedValues.sort(orderByTypes("vegetable", "meat", "fruit"))

console.log(sortedByType)
// Output shown as sorted values by type

We can also perform multi-level sorting by combining different sorting criteria:

// Multi-level sorting
const sortedMultiLevel = unsortedValues.sort(mergeComparator(orderByTypes("meat", "fruit", "dairy"), orderByName))

console.log(sortedMultiLevel)
// Output shown as multi-level sorted values

By utilizing these custom sorting functions, we can achieve intricate and flexible sorting behaviors for our data.

Feel free to experiment with the snippet provided to explore different sorting combinations and see the results in your browser console.

Answer №3

Provided that allRecords has already been sorted by type in such a way that all values with the same type are grouped together within the array (or if type is not present at all), then the following function will operate similarly to Object.assign():

function spliceBy<T, K extends keyof T> (key: K, target: T[], ...sources: Iterable<T>[]) {
  const groups: Map<T[K], T[]> = new Map()

  for (const source of sources) {
    for (const entry of source) {
      const value = entry[key]
      const oldEntries = groups.get(value)
      const entries = oldEntries || []

      if (!oldEntries) groups.set(value, entries)

      entries.push(entry)
    }
  }

  for (const [value, entries] of groups) {
    // find the end of a group of entries
    let found = false
    const index = target.findIndex(
      entry => entry[key] === value ? (found = true, false) : found
    )

    if (found) target.splice(index, 0, ...entries)
    else target.push(...entries)
  }

  return target
}

const allRecords = [{type:'fruit',name:'apple'},{type:'vegetable',name:'celery'},{type:'meat',name:'chicken'}]
const newRecords = [{type:'fruit',name:'pear'},{type:'vegetable',name:'spinach'},{type:'meat',name:'pork'}]

console.log(spliceBy('type', allRecords, newRecords))

Try it online!

If you prefer not to modify allRecords, you can use this alternative method:

console.log(spliceBy('type', [], allRecords, newRecords))

Answer №4

Here is a solution that should meet the requirements:

interface Data {
   category: string;
   itemName: string;
}

interface CategorizedData {
   [category: string]: items[];
}

private _dataByCategory: CategorizedData = {};

arrangeAndAdd(allData: Data[], newData: Data[]): Data[] {
   const dataArr: Data[] = [];
   this.add(allData);
   this.add(newData);
   Object.keys(this._dataByCategory).forEach(category => {
      this._dataByCategory[category].forEach(itemName => {
         dataArr.push({category, itemName});
      });
   });

   return dataArr;
}

private add(data: Data[]) {
   data.forEach(entry => {
      if (!this._dataByCategory[entry.category]) {
         this._dataByCategory[entry.category] = [];
      }
      this._dataByCategory[entry.category].push(entry.itemName);
   });
}

Answer №5

Although there may be other approaches with better performance, this solution is presented below:

const allData = [
  {
    category: 'electronics',
    item: 'smartphone'
  },
  {
    category: 'clothing',
    item: 'jacket'
  },
  {
    category: 'food',
    item: 'pizza'
  }
]

const newData = [
  {
    category: 'electronics',
    item: 'laptop'
  },
  {
    category: 'clothing',
    item: 'shoes'
  },
  {
    category: 'food',
    item: 'ice cream'
  }
]

function organizeAndMerge(...data){
    let combinedData = [];
    for(let datum of data){
        combinedData = combinedData.concat(datum);
    }
    combinedData.sort((d1, d2) => {
        if(d1.category == d2.category)
            return 0;
        else if(d1.category > d2.category)
            return 1;
        else
            return -1;
    })
    return combinedData;
}

let mergedData = organizeAndMerge(newData, allData);

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

Tips for utilizing a personalized design with the sort-imports add-on in VS Code?

After recently installing the VS Code extension sort-imports, I decided to give a custom style called import-sort-style-module-alias a try. Following what seemed to be the installation instructions (via npm i import-sort-style-module-alias) and updating m ...

In Python, I generate 2 separate lists, then proceed to sort one of them. As a result, both lists are

Within my code, I have a list named self.nodePathList which includes [782, 455, 231]. I then assign this list to another variable called self.sortedNodePath. After sorting self.sortedNodePath, I notice that both lists end up sorted. I carefully reviewed ...

How to quickly print multiple patterns with a variable on a single line using awk or sed

for item in $items; do occurrences=$(sed '/Error/!d;/$item/!d' $logfile | wc -l) #awk -v item=$item "/Error/ && /$item/" $logpath | wc -l echo "$occurrences - $item" done I have a solution using grep, however, I am not permitted to use i ...

Utilize switchMap to sequence calls

My goal is to execute rest requests sequentially using switchMap(...) from RxJs. Here is the object: export class Transaction { constructor( public id: string, public unique_id: string, public name: string, public status: string, pu ...

Unable to display HTML content on a page using the foreach callback in JavaScript

I have a function that iterates through each element of an array and generates HTML content on the page while updating some properties using elements from the array. I am utilizing forEach to iterate over the elements of the array and innerHTML to display ...

Why does Material-UI's "withStyles()" not function properly with a specified constructor in Typescript?

Update: Please note that there was an issue with the constructor generated by IntelliJ IDEA, but it has been fixed. You can find more details here: I'm exploring the use of Material-UI in my application, and I've encountered some challenges wit ...

Tips for retrieving JSON files within karma tests

I am currently working on developing a test for my TypeScript class that involves retrieving data from a JSON file. readData<T>(filePath: string): Promise<T> { return Qajax.getJSON(filePath); } For testing purposes, I am utilizing the Jas ...

An alternative method for substituting a character within a string (character array) using multiple characters in the C programming

Working with C, an unmanaged language rather than a managed one, has become somewhat unfamiliar to me. I have the task of creating a code block that scans through a character array and replaces every occurrence of '2' with 'Ba'. The cha ...

Obtaining the attribute value from a custom tag in Angular: A comprehensive guide

I am currently working on creating a customized password component in Angular5. I am having difficulty obtaining the minimum and maximum attribute values required to validate the password. I attempted to retrieve the values using JavaScript's getAttr ...

Employing ngModel in an option dropdown

I am having trouble passing an attribute from an API call to a submit function. I suspect it might have something to do with either the option select or how the input is being formatted. Encountering the error Error: No value accessor for form control wit ...

Unable to adjust the text color to white

As someone who is new to Typescript, I'm facing a challenge in changing the text color to white and struggling to find a solution. I'm hoping that someone can guide me in the right direction as I've tried multiple approaches without success ...

What is the best way to arrange items?

After creating a class and populating an array of objects with data, I am now faced with the task of sorting the entire array by a specific member of that class. How can I achieve this using the stable_sort() function? In my current setup, here's the ...

Comparing tsconfig.json and tsconfig.build.json: what sets them apart?

Guides like those found at 1 and 2 often recommend having two separate files - tsconfig.json and tsconfig.build.json - at the root level of an NPM monorepo for TypeScript projects. What are the distinctions between these files? Is it possible to consolida ...

Navigating the complexities of integrating Rollup, ES modules, TypeScript, and JSX can be a challenging endeavor due to

Lately, I've been learning about the tools mentioned in the title. However, I've encountered some bumps along the way, so I'm turning to StackOverflow for help. My Requirements I need something like Rollup to pack my stuff For bare module ...

What are the steps to transforming JSON data into an array or string format?

Not entirely certain about the appropriateness of these inquiries, but here it goes. I am dealing with an array value $custom_fields['user_gender'][0]. When this value is outputted, it looks like the following: a:2:{i:0;s:7:"Male";i:1;s:7:"Femal ...

When trying to upload a file with ng-upload in Angular, the error 'TypeError: Cannot read properties of undefined (reading 'memes')' is encountered

Struggling with an issue for quite some time now. Attempting to upload an image using ng-upload in angular, successfully saving the file in the database, but encountering a 'Cannot read properties of undefined' error once the upload queue is comp ...

Using Numpy to transform a sequence of whole numbers into hexadecimal format

I am faced with a challenge involving an image array transformed into a 16 x 1000000 array of 4 values each, represented as 2-bit integers using Numpy. A snippet of the array is shown below. My goal is to convert each column into a hexadecimal word in the ...

Best practices for efficiently extracting surface points from a Nx3 point cloud array using numpy

Imagine having a numpy array (with the shape of Nx3, where each row represents a point in 3D space as (x, y, z)) forming a point cloud. Now, I aim to create a heightmap from this point cloud by projecting it onto the xy plane. The goal is to identify the m ...

"Observed Issue: Ionic2 Array Fails to Update in HTML Display

I am struggling with updating an array in Ionic2 and Angular2. I have tried updating it on the front end but it's not working, even though it updates perfectly on the backend (ts) as confirmed by checking the console. I need assistance with this. Her ...

Utilize TypeScript function types in React for enhanced functionality

I have made the decision to refactor a project that was originally created with vanilla JavaScript and now I want to transition it to TypeScript. One issue I am facing is how to pass a function as a type on an interface. Although I referred to the TypeScr ...