web-dev-qa-db-ja.com

ES6でキーによるオブジェプロパティのフィルタリング

オブジェクトがあるとしましょう。

{
  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を使用してこれを達成するためのクリーンな方法を探しているので、スプレッド演算子を使用できます。ありがとうございます。

144
29er

許可された値のリストがある場合、次を使用してそれらをオブジェクトに簡単に保持できます。

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

雑学の目的で、元のデータから不要なフィールドを削除したい場合(ifい突然変異を伴うため、(は推奨しません推奨しません)) 、次のように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);

突然変異ベースのソリューションを示すためにこの例を含めていますが、使用することはお勧めしません。

341
ssube

ES6の構文を使用しても問題ない場合は、 here および here に記載されているように、これを実行する最も簡単な方法は次のとおりです。

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, ...

これはあなたの操作をワンライナーに減らすだけでなく、他のキーが何であるか(あなたが保存したいもの)を知っている必要もありません。

54
Ryan H.

最もきれいな方法は 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)
31
Guy Segev

これまでに述べられたことは何もありませんが、いくつかの答えを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);
12
Clemens Helm

1行のコードでの別の解決策

私は " 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);
11
Novy

一般的な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 } } ]
  )

下記のブラウザで結果を確認してください -

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

これら2つの機能は、さまざまな方法で実装できます。私はoreduceの中でArray.prototype.reduceにアタッチすることを選びました、しかし、あなたはまったく同じようにゼロからそれをすべて書くことができます

6
user633183

これが私の最近のやり方です。

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

ssube's 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のarrow関数のすばらしいところは、allowedをパラメータとして渡す必要がないことです。

3
Evan Plaice

あなたはこのようなことをすることができます:

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

2
Bouni

Object.entries()の代わりにObject.keys()を使用すると、filterを使用しないでより簡単なソリューションを実現できます。

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
},{})
2
Itai Noam

さて、このワンライナーはどうですか

    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
inabramova

ここでの答えは確かに適していますが、オブジェクト内のすべてのプロパティに対してホワイトリストをループ処理する必要があるため、少し時間がかかります。以下の解決策は、ホワイトリストを1回だけループ処理するため、大規模なデータセットに対してははるかに高速です。

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)
2
Joey Grisafe

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

0
dudi harush

[OK]を /これはどうですか:

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' }}
0
Alireza

ループ中に、特定のプロパティ/キーに遭遇したときは何もせずに残りを続けます。

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>
    );
});
0
Ryan Dhungel

この関数はキーのリストに基づいてオブジェクトをフィルタリングします。これは、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
    }
  }, {})
}
0
Khaled Osman

オブジェクトの特定のキーを削除できます

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;
0
Esin ÖNER

これを実現するには多くの方法があります。 受け入れられた答え は最も効果的ではないKeys-Filter-Reduceアプローチを使用します。

代わりに、for...inループを使用してオブジェクトのキーをループ処理するか、許可されているキーをループ処理し、 then を使用すると、パフォーマンスが最大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

a。単純なユースケースのベンチマークについては jsPerf を参照してください。結果はブラウザによって異なります。

0
d4nyll