ES6의 키로 객체 속성 필터링


266

객체가 있다고 가정 해 봅시다.

{
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

위의 객체를 필터링하여 다른 객체를 만들고 싶습니다.

 {
    item1: { key: 'sdfd', value:'sdfd' },
    item3: { key: 'sdfd', value:'sdfd' }
 }

Es6을 사용하여이를 수행하는 깨끗한 방법을 찾고 있으므로 스프레드 연산자를 사용할 수 있습니다.


ES6에는 객체 확산 연산자가 없으므로 여기서 필요하지 않습니다
Bergi


@ DanDascalescu 그러나이 답변 은 OP가 요구하는 것을 성취하는 ES6 방법을 제공합니까?
Jonathan H

키 / 값으로 필터링하려면 어떻게해야합니까?
jmchauv

답변:


503

허용되는 값 목록이 있으면 다음을 사용하여 객체에 쉽게 유지할 수 있습니다.

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.keys(raw)
  .filter(key => allowed.includes(key))
  .reduce((obj, key) => {
    obj[key] = raw[key];
    return obj;
  }, {});

console.log(filtered);

이것은 다음을 사용합니다.

  1. Object.keysraw(원래 데이터)의 모든 속성을 나열한 다음
  2. Array.prototype.filter 다음을 사용하여 허용 된 목록에있는 키를 선택합니다.
    1. Array.prototype.includes 그들이 있는지 확인하기 위해
  3. Array.prototype.reduce 허용 된 속성만으로 새 객체를 작성합니다.

이렇게하면 허용 된 속성으로 얕은 복사본이 만들어 지지만 속성 자체는 복사되지 않습니다.

당신은 또한 사용할 수있는 개체의 확산 연산자를 그들에게 (덕분에 돌연변이없이 일련의 객체를 생성하는 이 언급 대한 rjerue을 ) :

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.keys(raw)
  .filter(key => allowed.includes(key))
  .reduce((obj, key) => {
    return {
      ...obj,
      [key]: raw[key]
    };
  }, {});

console.log(filtered);

퀴즈의 목적으로 원치 않는 필드를 원래 데이터에서 제거하려면 ( 추악한 돌연변이가 포함되어 있기 때문에 권장 하지 않습니다 ) includes검사를 다음과 같이 뒤집을 수 있습니다.

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

Object.keys(raw)
  .filter(key => !allowed.includes(key))
  .forEach(key => delete raw[key]);

console.log(raw);

돌연변이 기반 솔루션을 보여주기 위해이 예제를 포함하고 있지만 사용하지 않는 것이 좋습니다.


1
감사합니다. 또한 '해체 구문을 사용하여 접근 방식을 찾았습니다. IE : const {item1, item3} = raw const newObject = {item1, item3}
29er

2
해체는 잘 작동하지만 순전히 컴파일 타임입니다. 동적 속성 목록으로 만들거나 복잡한 규칙을 제공 할 수 없습니다 (예 : 루프에 유효성 검사 콜백이 첨부 될 수 있음).
ssube

3
나는 이것을 충분히 투표 할 수 없다! 필터를 사용하고 for 루프에서 다른 객체를 줄이고 구성하지 않는 것이 좋습니다. 그리고 불변의 버전과 변경 가능한 버전을 명시 적으로 분리했다는 것이 놀랍습니다. +1
Sukima

3
빠른 경고 : Array.prototype.includesES6의 일부가 아닙니다. ECMAScript 2016 (ES7)에 도입되었습니다.
Vineet

3
불변의 방식으로 축소를 원한다면 함수 내용을 return {... obj, [key] : raw [key]}
rjerue

93

ES6 구문을 사용해도 괜찮다면 여기여기에 언급 된 것처럼 가장 깨끗한 방법 은 다음 과 같습니다 .

const data = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const { item2, ...newData } = data;

이제 다음이 newData포함됩니다.

{
  item1: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

또는 키를 문자열로 저장 한 경우 :

const key = 'item2';
const { [key]: _, ...newData } = data;

후자의 경우 [key]로 변환 item2되지만 const할당을 사용하고 있으므로 할당의 이름을 지정해야합니다. _버림 값을 나타냅니다.

더 일반적으로:

const { item2, ...newData } = data; // Assign item2 to item2
const { item2: someVarName, ...newData } = data; // Assign item2 to someVarName
const { item2: _, ...newData } = data; // Assign item2 to _
const { ['item2']: _, ...newData } = data; // Convert string to key first, ...

이렇게하면 작업이 한 줄짜리로 줄어들뿐만 아니라 다른 키가 무엇인지 (보존하려는) 알 필요가 없습니다.


5
" _버리는 가치를 나타냅니다"이것이 어디로 오나요? 처음
봤을

5
나는 이것이 JS 공동체에 의해 채택 된 협약이라고 믿는다. A _는 JS에서 사용할 수있는 유효한 변수 이름이지만 이름이 거의 없기 때문에 의도를 전달하려는 경우 실제로 그렇게 사용해서는 안됩니다. 따라서 신경 쓰지 않는 변수를 나타내는 방법으로 채택되었습니다. 여기에 대한 추가 토론이 있습니다 : stackoverflow.com/questions/11406823/…
Ryan H.

2
이것은 허용 된 답변보다 훨씬 깔끔하며 Object.keys ()로 새 배열을 만드는 오버 헤드와 filterand를 사용 하여 배열을 반복하는 오버 헤드를 피합니다 reduce.
ericsoco

3
@yhabib는 _중요하지 않습니다. 단지 변수 이름 일뿐입니다. 원하는 이름으로 바꿀 수 있습니다
Vic

1
@ Gerrat 일반화 된 솔루션이 사소한 한 줄짜리라고 생각하지 않습니다. 이를 위해 lodash의 omit기능인 lodash.com/docs/4.17.10#omit 또는 여기에 제공된 다른 솔루션 중 하나를 사용합니다.
Ryan H.

42

가장 깨끗한 방법은 Lodash # pick을 사용하는 것입니다.

const _ = require('lodash');

const allowed = ['item1', 'item3'];

const obj = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

const filteredObj = _.pick(obj, allowed)

3
런타임에 추가 프로젝트 종속성을 다운로드해야한다는 점을 지적하는 것이 중요합니다.
S. Esteves

1
_.omit (obj, [ "item2"])-lodash.omit은 lodash.pick과 반대입니다.
Alexander Solovyev

29

이전에 언급되지 않은 것은 아니지만 일반적인 ES6 답변에 대한 답변을 결합하면됩니다.

const raw = {
  item1: { key: 'sdfd', value: 'sdfd' },
  item2: { key: 'sdfd', value: 'sdfd' },
  item3: { key: 'sdfd', value: 'sdfd' }
};

const filteredKeys = ['item1', 'item3'];

const filtered = filteredKeys
  .reduce((obj, key) => ({ ...obj, [key]: raw[key] }), {});

console.log(filtered);


1
이것은 다른 것보다 훨씬 간단하고 성능이 뛰어난 솔루션입니다.)
pomeh

26

외부 라이브러리가없는 Modern JS의 한 줄에 있는 또 다른 솔루션 .

" Destructuring "기능을 가지고 놀고있었습니다 :

const raw = {
    item1: { key: 'sdfd', value: 'sdfd' },
    item2: { key: 'sdfd', value: 'sdfd' },
    item3: { key: 'sdfd', value: 'sdfd' }
  };
var myNewRaw = (({ item1, item3}) => ({ item1, item3 }))(raw);
console.log(myNewRaw);


2
var myNewRaw = (({ item1, item3}) => ({ item1, item3 }))(raw);구문 문제
Awol

1
여기에 요약 된 몇 가지 사항이 있습니다. 먼저, 먼저 함수 선언이 있습니다. 화살표 함수입니다 (객체를 가져 와서 객체를 반환합니다). function (obj) {return obj;}와 같습니다. 두 번째는 ES6이 미래를 파괴하는 것입니다. 함수 선언에서 객체를 구조화합니다 {item1, item3}. 그리고 마지막으로 스스로 기능을 호출합니다. 예를 들어 자체 호출 기능을 사용하여 범위를 관리 할 수 ​​있습니다. 그러나 여기서는 코드를 압축하는 것이 었습니다. 나는 그것이 분명하기를 바랍니다. 내가 뭔가를 그리워하면 자유롭게 추가하십시오.
Novy

5
이것은 선호하는 현대적인 접근 방식입니다.
mattdlockyer

20

이제 Object.fromEntries 메소드 를 사용하여 더 짧고 간단하게 만들 수 있습니다 (브라우저 지원 확인).

const raw = { item1: { prop:'1' }, item2: { prop:'2' }, item3: { prop:'3' } };

const allowed = ['item1', 'item3'];

const filtered = Object.fromEntries(
   Object.entries(raw).filter(
      ([key, val])=>allowed.includes(key)
   )
);

더 읽어보기 : Object.fromEntries


1
이것이 내가 생각하는 가장 좋은 방법입니다. 축소보다 훨씬 직관적입니다.
데이먼

10

generic을 추가하여 generic으로 ofilter구현할 oreduce수 있으므로 배열과 같은 방식으로 객체를 쉽게 필터링 할 수 있습니다.

const oreduce = (f, acc, o) =>
  Object
    .entries (o)
    .reduce
      ( (acc, [ k, v ]) => f (acc, v, k, o)
      , acc
      )

const ofilter = (f, o) =>
  oreduce
    ( (acc, v, k, o)=>
        f (v, k, o)
          ? Object.assign (acc, {[k]: v})
          : acc
    , {}
    , o
    )

여기서 작동하는 것을 볼 수 있습니다.

const data =
  { item1: { key: 'a', value: 1 }
  , item2: { key: 'b', value: 2 }
  , item3: { key: 'c', value: 3 }
  }

console.log
  ( ofilter
      ( (v, k) => k !== 'item2'
      , data
      )
      // [ { item1: { key: 'a', value: 1 } }
      // , { item3: { key: 'c', value: 3 } }
      // ]

  , ofilter
      ( x => x.value === 3
      , data
      )
      // [ { item3: { key: 'c', value: 3 } } ]
  )

아래의 브라우저에서 결과를 확인하십시오 –

이 두 기능은 여러 가지 방법으로 구현 될 수 있습니다. 나는 Array.prototype.reduce안쪽 에 붙이기로 선택 oreduce했지만 처음부터 쉽게 쓸 수 있습니다.


나는 당신의 해결책을 좋아하지만, 이것에 비해 얼마나 명확하고 더 효율적인지 모르겠습니다 .
Jonathan H

3
여기입니다 벤치 마크 솔루션이 가장 빠른 것으로 보여이.
Jonathan H

에서은 oreduce, 처음 acc에 그림자가되어 .reduce(acc, k),과에 ofiltero그림자입니다 - oreduce변수로 호출이라고 o하는 인 -뿐만 아니라?
Jarrod Mosen

ofilter변수 o그림자되지만 항상 동일한 입력 VAR를 가리키는; 그 여기에 그림자 이유가 있어요 때문에 이 동일합니다 - 축적은 ( acc)도 그림자이기 때문에 더 명확하게 보여줍니다 방법 람다 통해 데이터 이동; acc항상 동일하지 않습니다 바인딩 하지만 항상 현재 나타내는 지속적인 우리는 반환하고자하는 계산 결과의 상태를
감사합니다

코드가 잘 작동하고 메소드가 매우 훌륭하지만 코드 작성에 도움이되는 사람이 분명히 자바 스크립트에 대한 도움이 필요한 사람에게 궁금합니다. 나는 간결함을 원하지만 최소화 된 코드만큼 작습니다.
Paul G Mihai

7

이것이 최근에 내가 한 일입니다.

const dummyObj = Object.assign({}, obj);
delete dummyObj[key];
const target = Object.assign({}, {...dummyObj});

흠. 오래된 구문과 새로운 구문을 혼합 한 것 같습니다. Object.assign == ...당신은 쓸 수 const dummyObj = { ...obj }const target = { ...dummyObj }. 또한 후자는 dummyObj로 직접 작업 할 수 있기 때문에 후자는 전혀 필요하지 않습니다.
Andy

7

좋아,이 원 라이너는 어때?

    const raw = {
      item1: { key: 'sdfd', value: 'sdfd' },
      item2: { key: 'sdfd', value: 'sdfd' },
      item3: { key: 'sdfd', value: 'sdfd' }
    };

    const filteredKeys = ['item1', 'item3'];

    const filtered = Object.assign({}, ...filteredKeys.map(key=> ({[key]:raw[key]})));

2
모든 답변의 가장 놀라운 해결책. +1
Gergő Horváth

제거하려는 키만 알고 있다면 유지하려는 키가 아닌 경우 어떻게해야합니까?
Jason

6

여기에 대한 답변은 확실히 적합하지만 객체의 모든 속성에 대해 화이트리스트를 반복해야하므로 약간 느립니다. 아래의 솔루션은 화이트리스트를 한 번만 반복하므로 큰 데이터 세트의 경우 훨씬 빠릅니다.

const data = {
  allowed1: 'blah',
  allowed2: 'blah blah',
  notAllowed: 'woah',
  superSensitiveInfo: 'whooooah',
  allowed3: 'bleh'
};

const whitelist = ['allowed1', 'allowed2', 'allowed3'];

function sanitize(data, whitelist) {
    return whitelist.reduce(
      (result, key) =>
        data[key] !== undefined
          ? Object.assign(result, { [key]: data[key] })
          : result,
      {}
    );
  }

  sanitize(data, whitelist)

5

ssube의 answeranswer 에 대한 피기 백 .

재사용 가능한 버전이 있습니다.

Object.filterByKey = function (obj, predicate) {
  return Object.keys(obj)
    .filter(key => predicate(key))
    .reduce((out, key) => {
      out[key] = obj[key];
      return out;
    }, {});
}

그것을 사용하려면

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

var filtered = Object.filterByKey(raw, key => 
  return allowed.includes(key));
});

console.log(filtered);

ES6 화살표 기능의 아름다운 점은 allowed매개 변수 로 전달할 필요가 없다는 것 입니다.


4

다음과 같이 할 수 있습니다 :

const base = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const filtered = (
    source => { 
        with(source){ 
            return {item1, item3} 
        } 
    }
)(base);

// one line
const filtered = (source => { with(source){ return {item1, item3} } })(base);

이것은 작동하지만 명확 with하지 않으며 진술은 권장되지 않습니다 ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with ).


4

사용하지 않고 간단한 솔루션을 사용 filter하는 Object.entries()대신Object.keys()

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.entries(raw).reduce((acc,elm)=>{
  const [k,v] = elm
  if (allowed.includes(k)) {
    acc[k] = v 
  }
  return acc
},{})

3

이를 달성하는 방법에는 여러 가지가 있습니다. 허용 대답 가장 확대됨에없는 키 - 필터 - 절감 접근 방식을 사용합니다.

대신 for...in루프를 사용하여 객체의 키를 반복하거나 허용 된 키를 반복 한 다음 새 객체 구성하는 것이 ~ 50 % 더 성능 좋습니다.

const obj = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const keys = ['item1', 'item3'];

function keysReduce (obj, keys) {
  return keys.reduce((acc, key) => {
    if(obj[key] !== undefined) {
      acc[key] = obj[key];
    }
    return acc;
  }, {});
};

function forInCompose (obj, keys) {
  const returnObj = {};
  for (const key in obj) {
    if(keys.includes(key)) {
      returnObj[key] = obj[key]
    }
  };
  return returnObj;
};

keysReduce(obj, keys);   // Faster if the list of allowed keys are short
forInCompose(obj, keys); // Faster if the number of object properties are low

ㅏ. 간단한 사용 사례의 벤치 마크는 jsPerf 를 참조하십시오 . 브라우저마다 결과가 다릅니다.


3

객체에서 특정 키를 제거 할 수 있습니다

items={
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

// Example 1
var key = "item2";
delete items[key]; 

// Example 2
delete items["item2"];

// Example 3
delete items.item2;

3
const filteredObject = Object.fromEntries(Object.entries(originalObject).filter(([key, value]) => key !== uuid))

2
OP의 질문을 제공하는 다른 답변이 있으며 얼마 전에 게시되었습니다. 답변을 게시 할 때는 특히 오래된 질문에 답변 할 때 새 솔루션을 추가하거나 실질적으로 더 나은 설명을 추가하십시오.
help-info.de

2

간단한 방법! 이것을하기 위해.

const myData = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};
const{item1,item3}=myData
const result =({item1,item3})


실제로 여기에서 아무것도 필터링하지 않고 주어진 데이터를 파괴합니다. 그러나 데이터가 변경되면 어떻게됩니까?
Idris Dopico Peña

2

"신규"를 사용하는 다른 솔루션 Array.reduce 방법을 :

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = allowed.reduce((obj, key) => { 
  obj[key] = raw[key]; 
  return obj 
}, {})

console.log(filtered);

이 바이올린 에서 시연...


하지만 난에서 솔루션처럼 여기이 대답 사용 과 :Object.fromEntries Array.filterArray.includes

const object = Object.fromEntries( Object.entries(raw).filter(([key, value]) => allowed.includes(key)) );

이 바이올린 에서 시연 ...


Wilt, 두 번째 접근 방식은 작년에 제공된이 답변과 정확히 일치합니다. stackoverflow.com/a/56081419/5522000
Art Schmidt

@ArtSchmidt 귀하의 의견에 감사드립니다 : 긴 목록에서 하나를 놓쳤다. 그 대답을 대신 참조하겠습니다.
Wilt

1

좋아, 이건 어때?

const myData = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

function filteredObject(obj, filter) {
  if(!Array.isArray(filter)) {
   filter = [filter.toString()];
  }
  const newObj = {};
  for(i in obj) {
    if(!filter.includes(i)) {
      newObj[i] = obj[i];
    }
  }
  return newObj;
}

다음과 같이 호출하십시오.

filteredObject(myData, ['item2']); //{item1: { key: 'sdfd', value:'sdfd' }, item3: { key: 'sdfd', value:'sdfd' }}

1

이 함수는 키 목록을 기반으로 객체를 필터링합니다. reduce를 호출하기 전에 Array.filter를 사용할 필요가 없으므로 이전 답변보다 효율적입니다. O (n + 필터링)과 반대로 O (n)

function filterObjectByKeys (object, keys) {
  return Object.keys(object).reduce((accum, key) => {
    if (keys.includes(key)) {
      return { ...accum, [key]: object[key] }
    } else {
      return accum
    }
  }, {})
}

1

루프 중에 특정 속성 / 키가 발견되면 아무것도 반환하지 않고 나머지는 계속하십시오.

const loop = product =>
Object.keys(product).map(key => {
    if (key === "_id" || key === "__v") {
        return; 
    }
    return (
        <ul className="list-group">
            <li>
                {product[key]}
                <span>
                    {key}
                </span>
            </li>
        </ul>
    );
});

1

아직 아무도 이것을 제안하지 않은 것에 놀랐습니다. 유지하려는 키에 대해 매우 깨끗하고 명시 적입니다.

const unfilteredObj = {a: ..., b:..., c:..., x:..., y:...}

const filterObject = ({a,b,c}) => ({a,b,c})
const filteredObject = filterObject(unfilteredObject)

또는 더러운 라이너 하나를 원한다면 :

const unfilteredObj = {a: ..., b:..., c:..., x:..., y:...}

const filteredObject = (({a,b,c})=>({a,b,c}))(unfilteredObject);

이 방법은 원래 배열에없는 키를 추가합니다. 문제가 될 수도 있고 아닐 수도 있습니다. 최소한 지적해야합니다.
폰치에 토

0

또 다른 방법은 사용하는 것 Array.prototype.forEach()같은

const raw = {
  item1: {
    key: 'sdfd',
    value: 'sdfd'
  },
  item2: {
    key: 'sdfd',
    value: 'sdfd'
  },
  item3: {
    key: 'sdfd',
    value: 'sdfd'
  }
};

const allowed = ['item1', 'item3', 'lll'];

var finalObj = {};
allowed.forEach(allowedVal => {
  if (raw[allowedVal])
    finalObj[allowedVal] = raw[allowedVal]
})
console.log(finalObj)

원시 데이터에서 사용 가능한 키 값만 포함하므로 정크 데이터를 추가 할 수 없습니다.


0

그게 내 해결책이 될 것입니다.

const filterObject = (obj, condition) => {
    const filteredObj = {};
    Object.keys(obj).map(key => {
      if (condition(key)) {
        dataFiltered[key] = obj[key];
      }
    });
  return filteredObj;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.