Cấu trúc lại mảng JavaScript


16

Tôi có một mảng với các địa chỉ học sinh và phụ huynh.

Ví dụ,

  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'
  }
];

Tôi đang cố gắng định dạng lại kết quả này.

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'
        }
    ]
}
];

Cho đến nay tôi đã thử cách sau. Tôi không chắc đó có phải là cách đúng hay không.

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
Vì vậy, trong ngắn hạn - để giúp người đọc trong tương lai dễ dàng hơn - bạn muốn kết hợp parent_addressrelationshipnhập vào một parentđối tượng và hợp nhất chúng khi tìm thấy tên và địa chỉ email trùng lặp.
Lewis

2
Làm thế nào địa chỉ cha mẹ có thể được thực hiện? Tài sản nào nên được sử dụng để liên quan đến họ? Cảm ơn trước! :)
StepUp

Đoạn mã ở cuối không khớp với cấu trúc dữ liệu. Bạn nói const list = []lúc đầu, nhưng ở phía dưới, bạn lặp lại danh sách đó rõ ràng bằng cách lặp lại user[0]. Mã ví dụ của bạn phải nhất quán.
TKoL

@Lewis vâng, tôi muốn chính xác như bạn đã đề cập.
Kathy

@SteUp, những giá trị đó được lấy nó từ db hiện tại của tôi và tham gia với bảng sinh viên và phụ huynh. Những gì tôi chỉ có id của học sinh trong bảng phụ huynh.
Kathy

Câu trả lời:


12

Một cách tiếp cận sẽ là sử dụng .reduce()với một đối tượng như một bộ tích lũy. Đối với mỗi id, bạn có thể lưu trữ một đối tượng được liên kết với một mảng cha mẹ mà bạn có thể nối vào trong .reduce()cuộc gọi lại của mình bất cứ khi nào bạn gặp một đối tượng mới có cùng id. Sau đó, để có được một mảng các đối tượng từ đối tượng của bạn, bạn có thể gọi Object.values()

Xem ví dụ dưới đây:

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

Vì bạn đã đề cập đến việc bạn chưa quen với JS, nên có thể dễ hiểu hơn theo cách cấp bách hơn (xem các nhận xét về mã để biết chi tiết):

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


Cảm ơn, tôi sẽ kiểm tra chi tiết và tôi rất tồn tại để đọc mã của bạn.
Kathy

Ooh này là rắn. Đối tượng phá hủy trong cuộc reducegọi lại là tốt, nhưng có lẽ hơi nặng đối với người mới bắt đầu.
TKoL

1
@TKoL cảm ơn, tôi sẽ thử và thêm phiên bản "đơn giản hơn"
Nick Parsons

1
Phiên bản đơn giản hơn trông rất tuyệt!
TKoL

1
Cảm ơn bạn rất nhiều. Tôi đọc mã của bạn và dễ hiểu đặc biệt là trên đoạn mã thứ hai. Đánh giá cao câu trả lời của các thành viên khác là tốt. Một lần nữa, cảm ơn các bạn rất nhiều.
Kathy

5

Bạn có thể giảm mảng và tìm kiếm người dùng có cùng id và thêm thông tin gốc vào đó.

Nếu không tìm thấy người dùng, hãy thêm người dùng mới vào tập kết quả.

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

Tái cấu trúc dữ liệu như thế này là khá phổ biến và Array.reduce()được thiết kế cho nhiệm vụ. Đó là một cách khác nhau để xem mọi thứ và làm cho một số quen thuộc, nhưng sau khi bạn viết mã một vài lần, nó trở thành bản chất thứ hai.

reduce() được gọi trên một mảng và có hai tham số:

  1. một hàm sẽ được gọi cho mỗi phần tử trong mảng
  2. giá trị khởi đầu

Hàm của bạn sau đó được gọi cho từng phần tử với giá trị bắt đầu cho lần chạy đầu tiên hoặc giá trị trả về từ lệnh gọi hàm trước cho mỗi lần chạy tiếp theo, dọc theo phần tử mảng, chỉ mục vào mảng ban đầu và mảng ban đầu giảm () được gọi vào (hai cái cuối cùng thường bị bỏ qua và hiếm khi cần thiết). Nó sẽ trả về đối tượng hoặc bất cứ thứ gì bạn đang xây dựng với phần tử hiện tại được thêm vào và giá trị trả về đó được chuyển cho lệnh gọi tiếp theo tới hàm của bạn.

Đối với những thứ như thế này tôi thường có một đối tượng để giữ các khóa duy nhất ( idcho bạn), nhưng tôi thấy bạn muốn một mảng được trả về. Đó là một dòng để ánh xạ đối tượng và khóa vào một mảng và sẽ hiệu quả hơn khi sử dụng cơ chế thuộc tính đối tượng tích hợp thay vì mảng.find () để xem bạn đã thêm id chưa.

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

Bạn cần lặp lại hai lần bằng phương pháp hiện tại. Độ phức tạp là O (n ^ 2). (đối với Loop + indexOf)

Một cách tốt hơn là lập chỉ mục cho mảng và sử dụng khóa mảng để phát hiện và tìm kiếm trùng lặp.

Ví dụ:

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

Cảm ơn, tôi sẽ kiểm tra chi tiết và tôi rất tồn tại để đọc mã của bạn.
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
Một lời giải thích sẽ theo thứ tự. Ví dụ, bạn đã thay đổi những gì? Và tại sao?
Peter Mortensen

1

Bạn có thể sử dụng Mapbộ sưu tập để lưu trữ các mục độc đáo và chỉ cần điền vào đó bằng cách sử dụng 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));
});

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.