简体   繁体   中英

How to array on plain JS?

I'am not sure that it should be called normalization, but i didn't imagined better name, so the task: I have an array of objects (let's call it mainData which contain obj1 and obj2 ), one prop is array someData of object. The object inside someData and their amount vary. I want to get mainData with but each of containing object should have same obects inside someData like this: I have:

let obj1 = {
    someData: [
        {
            name: 'Name 1',
            value: 1111,
        },
        {
            name: 'Name 2',
            value: 2222,
        },
        {
            name: 'Name 3',
            value: 3333,
        }
    ]
}

let obj2 = {
    someData: [
        {
            name: 'Name 1',
            value: 1111,
        },
        {
            name: 'Name 2',
            value: 2222,
        },
        {
            name: 'Name 4',
            value: 4444,
        },
        {
            name: 'Name 5',
            value: 5555,
        }
    ]
}

I want:

let obj1 = {
    someData: [
        {
            name: 'Name 1',
            value: 1111,
        },
        {
            name: 'Name 2',
            value: 2222,
        },
        {
            name: 'Name 3',
            value: 3333,
        },
        {
            name: 'Name 4',
            value: null,
        },
        {
            name: 'Name 5',
            value: null,
        }        
    ]
}

let obj2 = {
    someData: [
        {
            name: 'Name 1',
            value: 1111,
        },
        {
            name: 'Name 2',
            value: 2222,
        },
        {
            name: 'Name 3',
            value: null,
        },
        {
            name: 'Name 4',
            value: 4444,
        },
        {
            name: 'Name 5',
            value: 5555,
        }
    ]
}

Try this. Loop through each array and check whether the object is there in the another array. If not push that with value null. Please find a sample below.

 let obj1 = { someData: [ { name: "Name 1", value: 1111 }, { name: "Name 2", value: 2222 }, { name: "Name 3", value: 3333 } ] }; let obj2 = { someData: [ { name: "Name 1", value: 1111 }, { name: "Name 2", value: 2222 }, { name: "Name 4", value: 4444 }, { name: "Name 5", value: 5555 } ] }; obj1.someData.forEach(obj => { const itemInSecondArray = obj2.someData.find( item => item.name === obj.name ); if (!itemInSecondArray) { obj2.someData.push({ name: obj.name, value: null }); } }); obj2.someData.forEach(obj => { const itemInFirstArray = obj1.someData.find( item => item.name === obj.name ); if (!itemInFirstArray) { obj1.someData.push({ name: obj.name, value: null }); } }); // Sort obj1.someData.sort((a, b) => (a.name < b.name)? -1: 1); obj2.someData.sort((a, b) => (a.name < b.name)? -1: 1); console.log(obj1); console.log(obj2);

You could store an array of unique names. And iterate through each data, keep the same if has the name, else add a new one with value of null

const getNames = arr => arr.map(el => el.name)
const buildNewDataFromUniqueNames = (arr, uniqueNames) =>
  uniqueNames.map(name => {
    const el = arr.find(el => el.name === name)
    return el || { name, value: null }
  })

const uniqueNames = Array.from(
  new Set([...getNames(data1), ...getNames(data2)])
)

console.log({ someData: buildNewDataFromUniqueNames(data1, uniqueNames) })
console.log({ someData: buildNewDataFromUniqueNames(data2, uniqueNames) })

Full code

 let { someData: data1 } = { someData: [ { name: 'Name 1', value: 1111 }, { name: 'Name 2', value: 2222 }, { name: 'Name 3', value: 3333 } ] } let { someData: data2 } = { someData: [ { name: 'Name 1', value: 1111 }, { name: 'Name 2', value: 2222 }, { name: 'Name 4', value: 4444 }, { name: 'Name 5', value: 5555 } ] } const getNames = arr => arr.map(el => el.name) const buildNewDataFromUniqueNames = (arr, uniqueNames) => uniqueNames.map(name => { const el = arr.find(el => el.name === name) return el || { name, value: null } }) const uniqueNames = Array.from( new Set([...getNames(data1), ...getNames(data2)]) ) console.log({ someData: buildNewDataFromUniqueNames(data1, uniqueNames) }) console.log({ someData: buildNewDataFromUniqueNames(data2, uniqueNames) })

Here is a generic function, which does not depend on hardcoded property names (like "name" or "value"), but takes the name of the "key" property as argument, and will set any other properties to null when needed.

The function uses a Map to guarantee efficient lookup of an item in the other array, avoiding a O(n²) time complexity (which you get with find and similar methods).

The result array will also be sorted by whatever the key property is:

 function alignArray(a, b, key="name") { if (!b.length) return [...a]; let template = {}; for (let prop in b[0]) template[prop] = null; let map = new Map(a.map(o => [o[key], o])); for (let o of b) { let match = map.get(o[key]); if (!match) map.set(o[key], ({ ...template, [key]: o[key] })); } return [...map.values()].sort((a, b) => +(a[key] > b[key]) || -(a[key] < b[key])); } // demo let obj1 = {someData: [{name: 'Name 1',value: 1111,},{name: 'Name 2',value: 2222,},{name: 'Name 3',value: 3333,}]} let obj2 = {someData: [{name: 'Name 1',value: 1111,},{name: 'Name 2',value: 2222,},{name: 'Name 4',value: 4444,},{name: 'Name 5',value: 5555,}]} obj1.someData = alignArray(obj1.someData, obj2.someData, "name"); obj2.someData = alignArray(obj2.someData, obj1.someData, "name"); console.log(obj1); console.log(obj2);

You could get all sored names and map this array with the data of the other arrays or take a new object with null values.

 const map = (source, i = 0) => name => source[i]?.name === name ? source[i++] : { name, value: null }, array1 = [{ name: 'Name 1', value: 1111 }, { name: 'Name 2', value: 2222 }, { name: 'Name 3', value: 3333 }], array2 = [{ name: 'Name 1', value: 1111 }, { name: 'Name 2', value: 2222 }, { name: 'Name 4', value: 4444 }, { name: 'Name 5', value: 5555 }], names = [...new Set([...array1, ...array2].map(({ name }) => name))].sort(), result1 = names.map(map(array1)), result2 = names.map(map(array2)); console.log(result1); console.log(result2);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM