【问题标题】:Loop through array with missing elements循环遍历缺少元素的数组
【发布时间】:2019-11-06 14:40:14
【问题描述】:

我有一个带有一些表格数据的 JSON 提要,我正在使用 Vue.js 来显示一个 HTML 表格:

<tr v-for="row, index in content">
    <td class="index" v-text="index + 1"></td>
    <td v-for="column in row" v-text="column"></td>
</tr>

此提要为每一行返回一个数组,但有些行具有命名键。使用这个简单的 foreach 循环,它会忽略键,这将生成一个无法以正确方式显示数据的表。

如何使用密钥生成表格?我已经考虑获得highest value from the keys 并使用Array.fill(),但我认为必须有更好的方法。

这是我的数据:

{
  "content": [
    [
      "",
      "In scope:",
      "Not in scope:"
    ],
    [
      "Cars",
      "",
      "X"
    ],
    [
      "Bikes",
      "X",
      ""
    ],
    {
      "0": "Houses",
      "2": "X"
    }
  ]
}

请注意,这是虚构数据,实际数据可能会有所不同,因此我无法找到具有固定列数的解决方案。

实际输出:

|        | In scope: | Not in scope: |
|--------|-----------|---------------|
| Cars   |           | X             |
| Bikes  | X         |               |
| Houses | X         |

预期输出:

|        | In scope: | Not in scope: |
|--------|-----------|---------------|
| Cars   |           | X             |
| Bikes  | X         |               |
| Houses |           | X             |

【问题讨论】:

  • 您是否能够预处理数据(在将其交给视图之前)?在这种情况下,您可能希望将其转换为已知结构,例如:jsfiddle.net/exh824v1/1 - 这是否符合您的要求?
  • 我希望第一个元素包含所有列标题定义,但这只是一个假设。
  • 从我的脑海中我只能想到你描述的Array.fill() 方式。如果有原生的 Vue.js 解决方案会很有趣。

标签: javascript arrays vue.js


【解决方案1】:

通过这个简单的 foreach 循环,它会忽略键

假设您指的是Array.prototype.forEach,处理函数函数的第二个参数是迭代索引:

let arr = ['zero', 'one'];
arr[10] = 'ten';

arr.forEach((value, index) => console.log(value, index));

【讨论】:

    【解决方案2】:

    对我来说,我认为问题在于循环随着索引移动,突然你没有那个索引。

    所以我相信会发生的是:

    它的循环 index=0 给出“自行车”

    比循环 index=1 给出“X”,

    比循环 index=2 给出“”(对象中的第三个成员)

    比你给它一个两个成员的对象,它从 0 到 1

    所以尝试保存为:

         - "0":"houses"
         - "1":""
         - "2":"X"
    

    【讨论】:

      【解决方案3】:

      您使用Array#fill 的想法对我来说似乎很好:您需要定义间隙的值(在您的情况下为空字符串)。

      但由于您的非数组对象的索引似乎总是数字,因此找到最大键会更容易一些。尽管 ES6 规范没有定义 Object.keys 返回的顺序,但所有当前的 JS 引擎都按数字顺序生成键(当键表示 64 位范围内的正整数时),因此您可以从中弹出最后一个值:

      column in Object.assign(Array(+Object.keys(row).pop()+1).fill(""), row)
      

      【讨论】:

      • Object.assign 适用于数组?整洁的。今天学到了新东西,谢谢!
      • 当然,它适用于任何对象,无论其原型如何。
      【解决方案4】:

      看起来您的第一行是标题行。如果您可以接受它作为以下项目长度的真实来源,则可以创建一个简单的函数来映射数组并为所有项目强制执行该长度。这将规范化项目,使它们成为数组,填充孔,删除超出长度的项目,并忽略对象上的非数字键:

      let o = {
          "content": [
            [
              "",
              "In scope:",
              "Not in scope:"
            ],
            [
              "Cars",
              "",
              "X"
            ],
            [
              "Bikes",
              "X",
              "",
              "extra data!"          // < will be removed 
            ],
            {
              "non number": "huh?",  // < will be removef
              "0": "Houses",         // will fill in index 1 with undefined
              "2": "X",
              
            }
          ]
        }
      const enforceLength = (l, arr) => arr.map(arr => Array.from({length: l, ...arr}))
      let l = o.content[0].length
      
      o.content = enforceLength(l, o.content)
      
      console.log(o.content)

      如果你把它放在你的组件的一个方法中,你可以简单地在模板中调用它,比如:

      <tr v-for="row, index in normalize(content)">
      

      【讨论】:

      • 非常好的解决方案
      【解决方案5】:

      数据并不理想,因为对象属性不假定编号索引(如果将其他数字声明为键,则该对象显然不会“填补空白”)。您可以映射到一个新数组,在 Vue 组件的 计算属性 中填写 elem[1] 上的任何 undefineds:

      computed: {
        contentAsArrays() {
          return this.content.map(e => {
            if (e[1] === undefined) e[1] = "";
            return e;
          });
        },
      },
      

      并在您的模板中引用此计算属性:

      <tr v-for="row, index in contentAsArrays">
      

      【讨论】:

      • 我没有对此投反对票,但我怀疑这不是一个很好的解决方案,因为它不够通用。 OP 说:the actual data can vary so I can't have a solution with a fixed number of columns. 所以e[1] 可能并不总是在未定义数据的位置。最后一个对象很容易是{ "0": "Houses", "1": "X" }
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-23
      • 2016-05-29
      相关资源
      最近更新 更多