Susunan ulang susunan JavaScript

16

Saya memiliki array dengan alamat siswa dan orang tua.

Sebagai contoh,

  const users = [{
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent_address: 'USA',
    relationship:'mother'
  },
  {
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent_address: 'Spain',
    relationship:'father'
  },
  {
    id: 2,
    name: 'Mark',
    email: '[email protected]',
    age: 28,
    parent_address: 'France',
    relationship:'father'
  }
];

Saya mencoba memformat ulang ini ke hasil berikut.

const list = [
{
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent: [
        {
            parent_address: 'USA',
            relationship:'mother'
        },{
            parent_address: 'Spain',
            relationship:'father'
        }
    ]
},
{
    id: 2,
    name: 'Mark',
    email: '[email protected]',
    age: 28,
    parent:[
        {
            parent_address: 'France',
            relationship:'father'
        }
    ]
}
];

Sejauh ini saya mencoba cara berikut. Saya tidak yakin itu cara yang benar atau tidak.

const duplicateInfo = [];
for (var i = 0; i < user[0].length; i++) {
    var parent = [];
    if (duplicateInfo.indexOf(user[0][i].id) != -1) {
        // Do duplicate stuff
    } else {
        // Do other
    }
    duplicateInfo.push(user[0][i].id);
}
kathy
sumber
1
Jadi singkatnya - untuk memudahkan pembaca di masa mendatang - Anda ingin menggabungkan parent_addressdan relationshipmasuk ke parentobjek, dan menggabungkan mereka ketika nama duplikat dan alamat email ditemukan.
Lewis
2
Bagaimana alamat induk dapat diambil? Properti apa yang harus digunakan untuk menghubungkannya? Terima kasih sebelumnya! :)
StepUp
Cuplikan kode pada akhirnya tidak cocok dengan struktur data. Anda katakan const list = []pada awalnya, tetapi di bagian bawah Anda beralih pada daftar itu dengan mengulangi user[0]. Kode contoh Anda harus konsisten.
TKol
@Lewis ya, saya ingin persis seperti yang Anda sebutkan.
kathy
@SteUp, nilai-nilai itu mengambilnya dari db saya yang ada dan bergabung dengan tabel siswa dan orang tua. Yang saya hanya punya id siswa di tabel induk.
kathy

Jawaban:

12

Salah satu pendekatan akan digunakan .reduce()dengan objek sebagai akumulator. Untuk setiap id, Anda dapat menyimpan objek terkait dengan array orangtua yang dapat Anda tambahkan dalam .reduce()panggilan balik Anda setiap kali Anda menemukan objek baru dengan id yang sama. Kemudian untuk mendapatkan sebuah array dari objek dari objek Anda, Anda dapat menghubungi Object.values()di atasnya

Lihat contoh di bawah ini:

const users = [{ id: 1, name: 'John', email: '[email protected]', age: 25, parent_address: 'USA', relationship: 'mother' }, { id: 1, name: 'John', email: '[email protected]', age: 25, parent_address: 'Spain', relationship: 'father' }, { id: 2, name: 'Mark', email: '[email protected]', age: 28, parent_address: 'France', relationship: 'father' } ];
const res = Object.values(users.reduce((acc, {parent_address, relationship, ...r}) => { // use destructuring assignment to pull out necessary values
  acc[r.id] = acc[r.id] || {...r, parents: []}
  acc[r.id].parents.push({parent_address, relationship}); // short-hand property names allows us to use the variable names as keys
  return acc;
}, {}));

console.log(res);

Karena Anda menyebutkan Anda baru di JS, mungkin lebih mudah untuk memahami dengan cara yang lebih penting (lihat komentar kode untuk detail):

const users = [{ id: 1, name: 'John', email: '[email protected]', age: 25, parent_address: 'USA', relationship: 'mother' }, { id: 1, name: 'John', email: '[email protected]', age: 25, parent_address: 'Spain', relationship: 'father' }, { id: 2, name: 'Mark', email: '[email protected]', age: 28, parent_address: 'France', relationship: 'father' } ];

const unique_map = {}; // create an object - store each id as a key, and an object with a parents array as its value
for(let i = 0; i < users.length; i++) { // loop your array object
  const user = users[i]; // get the current object
  const id = user.id; // get the current object/users's id
  
  if(!(id in unique_map)) // check if current user's id is in the the object
    unique_map[id] = { // add the id to the unique_map with an object as its associated value 
      id: id,
      name: user.name,
      email: user.email,
      age: user.age,
      parents: [] // add `parents` array to append to later
    }
    
  unique_map[id].parents.push({ // push the parent into the object's parents array
    parent_address: user.parent_address,
    relationship: user.relationship
  });
}

const result = Object.values(unique_map); // get all values in the unique_map
console.log(result);

Nick Parsons
sumber
Terima kasih, saya akan memeriksa detail dan saya sangat ada untuk membaca kode Anda.
kathy
Ooh ini solid. Destrukturisasi objek dalam reducecallback itu bagus, tapi mungkin agak berat untuk pemula.
TKol
1
@TKoL terima kasih, saya akan mencoba dan menambahkan versi "sederhana"
Nick Parsons
1
Versi sederhana terlihat hebat!
TKoL
1
Terima kasih banyak. Saya membaca kode Anda dan mudah dimengerti terutama pada cuplikan kode kedua. Menghargai jawaban anggota lain juga. Sekali lagi terima kasih banyak kawan.
Kathy
5

Anda dapat mengurangi array dan mencari pengguna dengan id yang sama dan menambahkan informasi induk ke dalamnya.

Jika pengguna tidak ditemukan, tambahkan pengguna baru ke set hasil.

const
    users = [{ id: 1, name: 'John', email: '[email protected]', age: 25, parent_address: 'USA', relationship: 'mother' }, { id: 1, name: 'John', email: '[email protected]', age: 25, parent_address: 'Spain', relationship: 'father' }, { id: 2, name: 'Mark', email: '[email protected]', age: 28, parent_address: 'France', relationship: 'father' }],
    grouped = users.reduce((r, { parent_address, relationship, ...user }) => {
        var temp = r.find(q => q.id === user.id );
        if (!temp) r.push(temp = { ...user, parent: []});
        temp.parent.push({ parent_address, relationship });
        return r;
    }, []);

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Nina Scholz
sumber
2

Restrukturisasi data seperti ini sangat umum dan Array.reduce()dirancang untuk tugas tersebut. Ini adalah cara berbeda untuk melihat sesuatu dan memerlukan waktu untuk membiasakan diri, tetapi setelah Anda menulis kode beberapa kali itu menjadi kebiasaan.

reduce() dipanggil pada array dan mengambil dua parameter:

  1. sebuah fungsi yang akan dipanggil untuk setiap elemen dalam array
  2. nilai awal

Fungsi Anda kemudian dipanggil untuk setiap elemen dengan nilai awal untuk proses pertama atau nilai kembali dari panggilan fungsi sebelumnya untuk setiap proses berikutnya, di sepanjang elemen array, indeks ke dalam array asli, dan array asli yang mengurangi () dipanggil (dua yang terakhir biasanya diabaikan dan jarang diperlukan). Itu harus mengembalikan objek atau apa pun yang Anda bangun dengan elemen saat ini ditambahkan, dan nilai pengembalian diteruskan ke panggilan berikutnya ke fungsi Anda.

Untuk hal-hal seperti ini saya biasanya memiliki objek untuk menyimpan kunci unik ( iduntuk Anda), tetapi saya melihat Anda ingin sebuah array dikembalikan. Itu satu baris untuk memetakan objek dan kunci ke array dan itu lebih efisien untuk menggunakan mekanisme properti objek built-in daripada array.find () untuk melihat apakah Anda sudah menambahkan id.

const users = [{
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent_address: 'USA',
    relationship:'mother'
  },
  {
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent_address: 'Spain',
    relationship:'father'
  },
  {
    id: 2,
    name: 'Mark',
    email: '[email protected]',
    age: 28,
    parent_address: 'France',
    relationship:'father'
  }
];

let combined = users.reduce(
  // function called for each element in the array
  (previous, element) => {
    // previous starts out as the empty object we pass as the second argument
    // and will be the return value from this function for every other element
    
    // create an object for the id on our 'previous' object if it doesn't exist,
    // if it does exist we will trust the name, email, and age from the first
    // instance
    previous[element.id] = previous[element.id] || {
      id: element.id,
      name: element.name,
      age: element.age,
      parents: []
    };
    
    // now add parent
    previous[element.id].parents.push({
      parent_address: element.parent_address,
      relationship: element.relationship
    });
    
    // return our updated object, which will be passed to the next call
    // and eventually returned
    return previous;
  },
  {} // initial value is an empty object, no ids yet
);

// transform object into array with elements in order by key
let list = Object.keys(combined).sort().map(key => combined[key]);

console.dir(list);

Jason Goemaat
sumber
1

Anda harus mengulang dua kali menggunakan metode saat ini. Kompleksitasnya adalah O (n ^ 2). (untuk Loop + indexOf)

Cara yang lebih baik adalah mengindeks array dan menggunakan kunci array untuk deteksi dan pencarian duplikasi.

Sebagai contoh:

const map = {};
users.forEach(user => {
    // Will return undefined if not exist
    let existing = map[user.id];
    if (!existing) {
        // If not exist, create new
        existing = {
            id: user.id,
            ...
            parents: [ {parent_address: user.parent_address, relationship: user.relationship ]
        }
    } else {
        // Otherwise, update only parents field
        // You can add other logic here, for example update fields if duplication is detected.
        existing.parents.push({parent_address: user.parent_address, relationship: user.relationship ]
        });
    }
    map[user.id] = existing;
})
// Convert the object to array
const list = map.values();
Anthony Poon
sumber
Terima kasih, saya akan memeriksa detail dan saya sangat ada untuk membaca kode Anda.
kathy
1
const users = [{
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent_address: 'USA',
    relationship:'mother'
  },
  {
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent_address: 'Spain',
    relationship:'father'
  },
  {
    id: 2,
    name: 'Mark',
    email: '[email protected]',
    age: 28,
    parent_address: 'France',
    relationship:'father'
  }
];
const updatedUsers = users.map(user => {
    return {
    id: user.id,
    name: user.name,
    email: user.email,
    age: user.age,
    parent: [{
        relationship: user.relationship,
        parent_address: user.parent_address,
    }]
}
})

const list = updatedUsers.reduce((acc, user) => {
    const findIndex = acc.findIndex(eachUser => eachUser.id === user.id && eachUser.email === user.email);
    if (findIndex < 0) {
        acc.push(user);
        return acc;
    } else {
    acc[findIndex].parent.push(user.parent);
    return acc; 
    }
}, []);
console.log(list)
Maharjun M
sumber
1
Penjelasan akan diurutkan. Misalnya, apa yang Anda ubah? Dan mengapa?
Peter Mortensen
1

Anda dapat menggunakan Mapkoleksi untuk menyimpan item unik dan cukup mengisinya menggunakan filter:

const unique = new Map(users.map(u=> 
    [u.id, {...u, parent: [...users.filter(f => f.id == u.id)]}]));

console.log(Array.from(unique, ([k, v])=> v)
    .map(s => ( { id: s.id, name: s.name, email: s.email, age:s.age, parent:s.parent })));

const users = [
  {
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent_address: 'USA',
    relationship: 'mother'
  },
  {
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent_address: 'Spain',
    relationship: 'father'
  },
  {
    id: 2,
    name: 'Mark',
    email: '[email protected]',
    age: 28,
    parent_address: 'France',
    relationship: 'father'
  }
];

const unique = new Map(users.map(u=> 
    [u.id, {...u, parent: [...users.filter(f => f.id == u.id)]}]));

console.log(Array.from(unique, ([k, v])=> v).map(s => ( 
    { id: s.id, name: s.name, email: s.email, age:s.age, parent:s.parent })));

StepUp
sumber
0

 const users = [{
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent_address: 'USA',
    relationship:'mother'
  },
  {
    id: 1,
    name: 'John',
    email: '[email protected]',
    age: 25,
    parent_address: 'Spain',
    relationship:'father'
  },
  {
    id: 2,
    name: 'Mark',
    email: '[email protected]',
    age: 28,
    parent_address: 'France',
    relationship:'father'
  }
];
ids = new Map()
for (const user of users) {
  var newuser;
  if (ids.has(user.id)) {
    newuser = ids.get(user.id);
  } else {
    newuser = {};
    newuser.id = user.id;
    newuser.name = user.name;
    newuser.email = user.email;
    newuser.age = user.age;
    newuser.parent = [];
  }
  relationship = {};
  relationship.parent_address = user.parent_address;
  relationship.relationship = user.relationship;
  newuser.parent.push(relationship)
  ids.set(user.id, newuser);
}
list = [ ...ids.values() ];
list.forEach((u) => {
  console.log(JSON.stringify(u));
});

JGFMK
sumber