JS:如果所有嵌套值都等于null

时间:2019-04-16 20:28:04

标签: javascript json object javascript-objects

从一个给定的数据结构(json文件)开始,我基本上需要呈现一个表。空的行和/或列不应呈现。我对JavaScript相当陌生,尝试了不同的方法(转换为数组并使用.map(),reduce()、. filter(),lodash等),但均未成功。我什至不知道解决问题的最佳方法是什么。 (或者可能是什么搜索字词。)

“行键”(例如:mo,tu,we,th,fr)和“列键”(john,hane,doe)都不是已知的并且可以变化。

完整示例:https://jsbin.com/rafeyasena/edit?js,output

"groupA": {
    "mo": { "john": 8, "jane": 5, "doe": null },
    "tu": { "john": 8, "jane": 5, "doe": null },
    "we": { "john": 5, "jane": 9, "doe": null },
    "th": { "john": 6, "jane": 3, "doe": null },
    "fr": { "john": null, "jane": null, "doe": null }
  }

可能的结果数据结构

const header = ["John", "Jane"];
const content = [
 "mo": {[ 8, 5 ]},
 "tu": {[ 8, 5 ]},
 "we": {[ 5, 9 ]},
 "th": {[ 6, 3 ]}
]

预期结果(前端,React):

   | John | Jane |
---|------|--------
mo |  8   |  5   |
tu |  8   |  5   |
we |  5   |  9   |
th |  6   |  3   |

到目前为止我尝试过的是: 如果它不再包含键/值(Delete null values in nested javascript objects),我能够删除所有null值和相应的键(https://medium.com/@hellotunmbi/how-to-deploy-angular-application-to-heroku-1d56e09c5147)-我面临着挑战,即要找出所有剩余的键来建立表头。 (在下面的示例中,这只会是John和Jane-因此基本上是一种迭代所有键并记录至少存在一次的每个键的方法)。所以我当前的数据看起来像这样(但是我不确定这是否是最好的方法):

"groupA": {
    "mo": { "john": 8, "jane": 5, },
    "tu": { "john": 8, "jane": 5, },
    "we": { "john": 5, "jane": 9, },
    "th": { "john": 6, "jane": 3, }
  }

3 个答案:

答案 0 :(得分:0)

我只是将数据表示为2D数组(这使得渲染更容易):

 const columnNames = [""];
 const rows = [columnNames];

  for(const [rowName, values] of Object.entries(groupA)) {
     const row = [rowName];
     for(const [columnName, value] of Object.entries(values)) {
        let position = columnNames.indexOf(columnName);
        if(value === null) continue;
        if(position === -1)
          position = columnNames.push(columnName) - 1;
        row[position] = value;
     }
     rows.push(row);
 }

 // just some debugging:   
 console.log( rows.map(row => row.map(it => (it || "").padStart(10)).join("|")).join("\n") );

答案 1 :(得分:0)

I think creating that latter format (with the nulls removed) is a very useful first step. From there you could write something like this to get it into a variant of your target format:

const uniqKeys = (obj) => [... new Set(Object.values(obj).flatMap(Object.keys))]

const transform = (group, headers = uniqKeys(group)) => ({
  headers,
  content: Object.entries(group).reduce(
    (a, [k, v]) => ({...a, [k]: headers.map(h => v[h])}),
    {}
  )
})


const groupA = {mo: {john: 8, jane: 5}, tu: {john: 8, jane: 5}, we: {john: 5, jane: 9}, th: {john: 6, jane: 3}}

console.log(transform(groupA))

Note that the target is a little different than your request, as your example content isn't legal JS ({[ 8, 5 ]} doesn't make sense) but I think it captures the spirit of it, returning something like:

{
  headers: ['john', 'jane'],
  content: {
    mo: [8, 5],
    tu: [8, 5],
    we: [5, 9],
    th: [6, 3]
  }
}

Note that this function is a little more general than the requirements, as you could supply it a list of headers and only extract those from the data.

答案 2 :(得分:0)

看看object-scan。一旦绕过它的工作原理,这种操作就相对容易了。这是您回答问题的方式

const objectScan = require('object-scan');

const isNullObject = (obj) => (
  obj instanceof Object
  && !Array.isArray(obj)
  && Object.values(obj).every((e) => e === null)
);

const prune = (data) => objectScan(['**'], {
  rtn: 'count',
  filterFn: ({ value, parent, property }) => {
    if (isNullObject(value)) {
      delete parent[property];
      return true;
    }
    return false;
  }
})(data);

const stats = {
  groupA: {
    mo: { john: 8, jane: 5, doe: null },
    tu: { john: 8, jane: 5, doe: null },
    we: { john: 5, jane: 9, doe: null },
    th: { john: 6, jane: 3, doe: null },
    fr: { john: null, jane: null, doe: null }
  }
};

console.log(prune(stats)); // return number of replaces
// => 1

console.log(stats);
// => { groupA:
//    { mo: { john: 8, jane: 5, doe: null },
//      tu: { john: 8, jane: 5, doe: null },
//      we: { john: 5, jane: 9, doe: null },
//      th: { john: 6, jane: 3, doe: null } } }