자바 스크립트 배열 구조


16

학생 및 학부모 주소가있는 배열이 있습니다.

예를 들어

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

지금까지 나는 다음과 같은 방법을 시도했다. 그것이 올바른 방법인지 확실하지 않습니다.

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
요컨대, 미래의 독자들이 더 쉽게 읽을 수 있도록하기 위해, 당신 은 객체 를 결합 하여 객체 에 결합 parent_address하고 , 중복 된 이름과 이메일 주소가 발견 될 때 그것들을 병합하고자합니다. relationshipparent
Lewis

2
부모의 주소를 어떻게 알 수 있습니까? 그것들을 연관시키기 위해 어떤 재산을 사용해야합니까? 미리 감사드립니다! :)
StepUp

끝에있는 코드 스 니펫이 데이터 구조와 일치하지 않습니다. 당신은 말을 const list = []처음,하지만 그 목록을 통해 아래 당신을 반복 처리에 분명히하여 이상 반복 user[0]. 예제 코드는 일관성이 있어야합니다.
TKoL December

@Lewis 네, 당신이 언급 한 것처럼 정확하게 원합니다.
kathy

@SteUp, 그 값은 기존 DB에서 값을 검색하여 학생 및 부모 테이블과 조인합니다. 부모 테이블에 학생 ID 만있는 것.
kathy

답변:


12

한 가지 방법은 .reduce()객체와 함께 누산기로 사용하는 것입니다. 각 ID에 대해 동일한 ID를 가진 새 객체가 발생할 때마다 .reduce()콜백에 추가 할 수있는 부모 배열을 사용하여 연결된 객체를 저장할 수 있습니다 . 그런 다음 개체에서 개체의 배열을 얻을, 당신은 호출 할 수 있습니다 Object.values()그것을

아래 예를 참조하십시오.

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를 처음 사용한다고 언급 했으므로보다 필수적인 방식으로 이해하는 것이 더 쉬울 수 있습니다 (자세한 내용은 코드 주석 참조).

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


감사합니다. 자세한 내용을 확인하고 코드를 읽을 수있는 존재입니다.
kathy

아 이건 견고 해요 reduce콜백 에서 객체 파괴 는 훌륭하지만 초보자에게는 약간 무겁습니다.
TKoL December

1
@TKoL, 감사합니다. "간단한"버전을 추가해 보도록하겠습니다
Nick Parsons

1
더 간단한 버전은 멋지게 보입니다!
TKoL December

1
정말 고맙습니다. 코드를 읽고 특히 두 번째 코드 스 니펫에서 이해하기 쉽습니다. 다른 회원의 답변에도 감사드립니다. 다시 한번 감사드립니다.
kathy

5

배열을 줄이고 동일한 ID를 가진 사용자를 검색하고 상위 정보를 추가 할 수 있습니다.

사용자를 찾을 수 없으면 결과 세트에 새 사용자를 추가하십시오.

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

이와 같은 데이터 구조 조정은 매우 일반적이며 Array.reduce() 작업을 위해 설계되었습니다. 다른 방법으로 볼 수 있고 익숙해 지지만 코드를 몇 번 작성한 후에는 두 번째 특성이됩니다.

reduce() 배열에서 호출되며 두 개의 매개 변수를 사용합니다.

  1. 배열의 각 요소에 대해 호출되는 함수
  2. 시작 값

그런 다음 각 요소마다 함수가 호출 됩니다. 배열 요소를 따라 처음 실행 또는 이후의 각 실행에 대한 이전의 함수 호출의 반환 값의 시작 값, 원래의 배열에 인덱스 및 감소 원래 배열 () 에 호출되었습니다 (마지막 두 개는 일반적으로 무시되며 거의 필요하지 않습니다). 객체 또는 현재 요소가 추가 된 상태로 빌드해야하며 반환 값은 다음 함수 호출에 전달됩니다.

이와 같은 것들에는 일반적으로 고유 키를 유지하는 객체가 id있지만 배열을 반환하려는 것을 알 수 있습니다. 이것은 객체와 키를 배열에 매핑하는 한 줄이며 array.find () 대신 내장 객체 속성 메커니즘을 사용하여 이미 id를 추가했는지 확인하는 것이 더 효율적입니다.

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

현재 방법을 사용하여 두 번 반복해야합니다. 복잡도는 O (n ^ 2)입니다. (for 루프 + indexOf)

더 좋은 방법은 배열을 색인화하고 복제 감지 및 검색에 배열 키를 사용하는 것입니다.

예를 들면 다음과 같습니다.

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

감사합니다. 자세한 내용을 확인하고 코드를 읽을 수있는 존재입니다.
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
순서대로 설명하겠습니다. 예, 무엇을 바 꾸었습니까? 그리고 왜?
Peter Mortensen

1

Mapcollection을 사용 하여 고유 항목을 저장하고 다음을 사용하여 채울 수 있습니다 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));
});

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.