4

This previous question comes closest to what I am curious of. I've tried several variations of indexOf() and filter() to no success

I have an arrays of objects (exampleDat):

[{id:1, value:"100", name:"dog", D1: 10, D2: 67, D3: 33},
{id:2, value:"200", name:"cat", D1: 66, D2: 41, D3: 34},
{id:3, value:"300", name:"fish", D1: 23, D2: 45, D3:},
{id:4, value:"400", name:"mouse", D1: 13, D2: 55, D3:},
{id:5, value:"500", name:"snake", D1: 7, D2: 9, D3:}]

In a different function, I return an array of which of these 'keys' I need. This array changes dynamically, so its not possible to type them all out. For example any of the following examples are viable,

useThese1 = ['D1','D2'] //Want exampleDat returned with only these key,value 'columns' returned
useThese2 = ['id','D1','D2','D3'] //Want exampleDat return with only these key,value 'columns' returned
useThese3 = ['value','D2','D3'] //Want exampleDat returned with only these key,value 'columns' returned

So I need to dynamically map the values in a useThese array to the exampleDat array

If I knew the exact columns, I could hand type it ala:

exampleDat.map(d => {return {D1: d.D1, D2: d.D2}})

But I need something like:

dat.map(d => useThese1.map(g =>  {return {something?}}) ???

In R, it would simply and easily be exampleDat[,colnames(exampleDat) %in% useThese1]

6 Answers 6

5

You could map the new keys.

const
    mapWith = (array, keys) => array.map(o => Object.fromEntries(keys.map(k => [k, o[k]]))),
    data = [{ id: 1, value: "100", name: "dog", D1: 10, D2: 67, D3: 33 }, { id: 2, value: "200", name: "cat", D1: 66, D2: 41, D3: 34 }, { id: 3, value: "300", name: "fish", D1: 23, D2: 45, D3:97}, { id: 4, value: "400", name: "mouse", D1: 13, D2: 55, D3:98}, { id: 5, value: "500", name: "snake", D1: 7, D2: 9, D3:99}],
    result1 = mapWith(data, ['D1', 'D2']),
    result2 = mapWith(data, ['id', 'D1', 'D2', 'D3']),
    result3 = mapWith(data, ['value', 'D2', 'D3']);

console.log(result1);
console.log(result2);
console.log(result3);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Object.fromEntries are relatively recent, but easily polyfilled.

Sign up to request clarification or add additional context in comments.

1 Comment

That's a better approach than mine, not sure why I didn't think of that!
3

Here is my solution. This uses the ES5 Javascript functions

const selectKeys = (keys, data) => {
    return data.map(item => keys.reduce((prev, key) => {
        prev[key] = item[key]
        return prev
    }, {}))
}

const selData1 = selectKeys(useThese1, data)
const selData2 = selectKeys(useThese2, data)
const selData3 = selectKeys(useThese3, data)

Comments

1

You can do something like this

const arr = [
  { id: 1, value: "100", name: "dog", D1: 10, D2: 67, D3: 33 },
  { id: 2, value: "200", name: "cat", D1: 66, D2: 41, D3: 34 },
  { id: 3, value: "300", name: "fish", D1: 23, D2: 45, D3: 34 },
  { id: 4, value: "400", name: "mouse", D1: 13, D2: 55, D3: 34 },
  { id: 5, value: "500", name: "snake", D1: 7, D2: 9, D3: 34 }
];

function dynamicFilter(data, requiredKeys) {
    return data.map((item) => {
        const result = {};
        requiredKeys.forEach(key => result[key] = item[key]);
        return result;
    });
}

console.log(dynamicFilter(arr, ['D1','D2']));
console.log(dynamicFilter(arr, ['id','D1','D2','D3']));

Comments

1

You can do something like this:

const arr = [{id:1, value:"100", name:"dog", D1: 10, D2: 67, D3: 33}, {id:2, value:"200", name:"cat", D1: 66, D2: 41, D3: 34}, {id:3, value:"300", name:"fish", D1: 23, D2: 45, D3:11}, {id:4, value:"400", name:"mouse", D1: 13, D2: 55, D3:11}, {id:5, value:"500", name:"snake", D1: 7, D2: 9, D3:11}];

const useThese1 = ['D1','D2'];
const useThese2 = ['id','D1','D2','D3'];
const useThese3 = ['value','D2','D3'];

const getResult = (keys) => arr.map(v => keys.reduce((a, c) => (a[c] = v[c], a), {}));

[useThese1, useThese2, useThese3].forEach(v => console.log(getResult(v)));

Comments

0

Here's an imperative way to do it. It could be shortened with ES6 array methods.

let exampleDat = [
  {id:1, value:"100", name:"dog", D1: 10, D2: 67, D3: 33},
  {id:2, value:"200", name:"cat", D1: 66, D2: 41, D3: 34},
  {id:3, value:"300", name:"fish", D1: 23, D2: 45, D3: 8},
  {id:4, value:"400", name:"mouse", D1: 13, D2: 55, D3: 8},
  {id:5, value:"500", name:"snake", D1: 7, D2: 9, D3: 8}
],
useThese1 = ['D1','D2']

function getColumns(data, useWhich){
  let result = [];
  for(let row of data){
    let keys = Object.keys(row);
    let filteredRow = {};
    for(let key of keys){
      if(useWhich.includes(key)){
        filteredRow[key] = row[key];
      }
    }
    result.push(filteredRow);  
  }
  return result;
}

console.log(getColumns(exampleDat, useThese1));

Comments

0

Here's a "for dummies" version of the accepted answer.
(The more verbose variable names helped me understand how the algorithm works.)

const
  selectColumns = (unfilteredData, colsToKeep) => 
    unfilteredData.map(row =>
      Object.fromEntries(colsToKeep.map( col => [col, row[col]] )
    )
  ),

  data = [
    { id: 1, value: "100", name: "dog", D1: 10, D2: 67, D3: 33 },
    { id: 2, value: "200", name: "cat", D1: 66, D2: 41, D3: 34 },
    { id: 3, value: "300", name: "fish", D1: 23, D2: 45, D3:97 },
    { id: 4, value: "400", name: "mouse", D1: 13, D2: 55, D3:98 },
    { id: 5, value: "500", name: "snake", D1: 7, D2: 9, D3:99 }
  ],

  colNames1 = ['D1', 'D2'],
  result1 = selectColumns(data, colNames1);
console.log(result1);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.