JavaScript dizi yapısı


16

Öğrenci ve veli adresleri olan bir dizim var.

Örneğin,

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

Bunu aşağıdaki sonuca göre yeniden biçimlendirmeye çalışıyorum.

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

Şimdiye kadar şu şekilde denedim. Bunun doğru yol olduğundan emin değilim.

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);
}

1
Kısacası - gelecekteki okuyucular için kolaylaştırmak için - bir nesneyi birleştirmek parent_addressve relationshipbir parentnesnede birleştirmek ve yinelenen bir ad ve e-posta adresi bulunduğunda bunları birleştirmek istiyorsunuz .
Lewis

2
Ebeveyn adresi nasıl alınabilir? Bunları ilişkilendirmek için hangi özellikler kullanılmalıdır? Şimdiden teşekkürler! :)
StepUp

Sondaki kod snippet'i veri yapısıyla eşleşmiyor. const list = []İlk başta söylüyorsunuz , ancak en altta görünüşte tekrarlayarak bu liste üzerinde yineliyorsunuz user[0]. Örnek kodunuz tutarlı olmalıdır.
TKoL

@Yeni evet, aynen bahsettiğin gibi istiyorum.
kathy

@SteUp, bu değer benim mevcut db almak ve öğrenci ve üst tablo ile katılmak. Üst tabloda yalnızca öğrencinin kimliğine sahip olduğum.
kathy

Yanıtlar:


12

Bir yaklaşım .reduce(), bir nesne ile akümülatör olarak kullanmak olacaktır . Her kimlik için, aynı kimliğe sahip yeni bir nesneyle karşılaştığınızda , .reduce()geri çağrınıza ekleyebileceğiniz bir ebeveynler dizisiyle ilişkilendirilmiş bir nesneyi depolayabilirsiniz . Ardından nesneden nesneleri dizisini almak için, Arayabileceğin Object.values()üzerinde

Aşağıdaki örneğe bakın:

const users = [{ id: 1, name: 'John', email: 'johnson@mail.com', age: 25, parent_address: 'USA', relationship: 'mother' }, { id: 1, name: 'John', email: 'johnson@mail.com', age: 25, parent_address: 'Spain', relationship: 'father' }, { id: 2, name: 'Mark', email: 'mark@mail.com', 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);

JS'de yeni olduğunuzdan bahsettiğinizden, daha zorunlu bir şekilde anlamak daha kolay olabilir (ayrıntılar için kod yorumlarına bakın):

const users = [{ id: 1, name: 'John', email: 'johnson@mail.com', age: 25, parent_address: 'USA', relationship: 'mother' }, { id: 1, name: 'John', email: 'johnson@mail.com', age: 25, parent_address: 'Spain', relationship: 'father' }, { id: 2, name: 'Mark', email: 'mark@mail.com', 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);


Teşekkürler, ayrıntıları kontrol edeceğim ve kodunuzu okumak için çok varım.
kathy

Ooh bu sağlam. Geri aramadaki nesne yıkımı reducegüzel, ama belki de yeni başlayanlar için biraz ağır.
TKoL

1
@TKoL teşekkürler, "daha basit" bir sürüm ekleyeceğim
Nick Parsons

1
Daha basit sürüm harika görünüyor!
TKoL

1
Çok teşekkür ederim. Kodunuzu okudum ve özellikle ikinci kod snippet'inde anlaşılması kolay. Diğer üyelerin cevabına da teşekkür ederiz. Tekrar, çok teşekkürler çocuklar.
kathy

5

Diziyi azaltabilir ve aynı kimliğe sahip bir kullanıcı arayabilir ve üst bilgiyi buna ekleyebilirsiniz.

Kullanıcı bulunamazsa, sonuç kümesine yeni bir kullanıcı ekleyin.

const
    users = [{ id: 1, name: 'John', email: 'johnson@mail.com', age: 25, parent_address: 'USA', relationship: 'mother' }, { id: 1, name: 'John', email: 'johnson@mail.com', age: 25, parent_address: 'Spain', relationship: 'father' }, { id: 2, name: 'Mark', email: 'mark@mail.com', 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; }


2

Bunun gibi verilerin yeniden yapılandırılması oldukça yaygındır ve Array.reduce()görev için tasarlanmıştır. Bir şeyleri izlemenin farklı bir yoludur ve alışmak biraz zaman alır, ancak kodu birkaç kez yazdıktan sonra ikinci doğa olur.

reduce() bir dizide çağrılır ve iki parametre alır:

  1. dizideki her öğe için çağrılacak bir işlev
  2. başlangıç ​​değeri

Daha sonra işleviniz , ilk öğe için başlangıç ​​değeri veya sonraki her bir işlem için önceki işlev çağrısından önceki değer çağrısı, dizi öğesi boyunca, orijinal dizinin dizinine ve () değerini azaltan orijinal diziye sahip her öğe için çağrılır . çağrıldı (son ikisi genellikle yok sayılır ve nadiren ihtiyaç duyulur). Geçerli öğeyi ekleyerek nesneyi veya oluşturduğunuz her şeyi döndürmelidir ve bu dönüş değeri işlevinize bir sonraki çağrıya aktarılır.

Bu gibi şeyler için genellikle ( idsizin için) benzersiz anahtarları tutmak için bir nesne var , ama bir dizi döndürmek istediğinizi görüyorum. Bu, nesneyi ve anahtarları bir diziyle eşleştirmek için kullanılan bir satırdır ve zaten bir kimlik ekleyip eklemediğinizi görmek için array.find () yerine yerleşik nesne özellik mekanizmasını kullanmak daha etkilidir.

const users = [{
    id: 1,
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    parent_address: 'USA',
    relationship:'mother'
  },
  {
    id: 1,
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    parent_address: 'Spain',
    relationship:'father'
  },
  {
    id: 2,
    name: 'Mark',
    email: 'mark@mail.com',
    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);


1

Geçerli yöntemi kullanarak iki kez yinelemeniz gerekir. Karmaşıklık O (n ^ 2) 'dir. (Loop + indexOf için)

Daha iyi bir yol diziyi dizine eklemek ve çoğaltma algılama ve arama için dizi anahtarını kullanmaktır.

Örneğin:

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();

Teşekkürler, ayrıntıları kontrol edeceğim ve kodunuzu okumak için çok varım.
kathy

1
const users = [{
    id: 1,
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    parent_address: 'USA',
    relationship:'mother'
  },
  {
    id: 1,
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    parent_address: 'Spain',
    relationship:'father'
  },
  {
    id: 2,
    name: 'Mark',
    email: 'mark@mail.com',
    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)

1
Bir açıklama yapılabilir. Örneğin, neyi değiştirdiniz? Ve neden?
Peter Mortensen

1

Sen kullanabilirsiniz Mapbenzersiz öğeleri saklamak ve sadece kullanarak doldurmak için toplama 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: 'johnson@mail.com',
    age: 25,
    parent_address: 'USA',
    relationship: 'mother'
  },
  {
    id: 1,
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    parent_address: 'Spain',
    relationship: 'father'
  },
  {
    id: 2,
    name: 'Mark',
    email: 'mark@mail.com',
    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 })));


0

 const users = [{
    id: 1,
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    parent_address: 'USA',
    relationship:'mother'
  },
  {
    id: 1,
    name: 'John',
    email: 'johnson@mail.com',
    age: 25,
    parent_address: 'Spain',
    relationship:'father'
  },
  {
    id: 2,
    name: 'Mark',
    email: 'mark@mail.com',
    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));
});

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.