【问题标题】:Efficient method to join the columns using arrays使用数组连接列的有效方法
【发布时间】:2021-10-24 10:23:13
【问题描述】:

问题: 我需要通过识别标题名称来合并列,并使用以下代码按需要工作。

代码效率非常低,因为我使用 eval 来完成这项工作,我相信它会导致不必要的多次传递,不建议这样做。有没有办法优化我的代码来合并列? 我的代码仅适用于一项水果,因为“CriteriaMatchArray”对于许多项目我需要再次将结果作为输入传递并运行它导致效率低下。

https://docs.google.com/spreadsheets/d/18FSwIDZ5H5nqrbwq-VIMoHouW6f0cSZ7sTIgN9RxBc0/edit?usp=sharing

这是图片:https://i.stack.imgur.com/A2d6d.png

因此最终结果只是如图所示的二维数组

下面有代码

 <!DOCTYPE html>
<html>

<body>

<script>
    var table = [
        ["Sl.no","fruits 1", "fruits 2", "fruits 3", "fruits 4", "fruits 5", "vegetables 1", "vegetables 2"],
        ["1","banana", "apple", "orange", "", "", "carrot", "cabbage"],
        ["2","watermelon", "apple", "orange", "", "", "beans", ""]
    ]

    //document.write(JSON.stringify(table))

    var str = [],
        m = [];
    var firstJoiningPosition = -1;
    CriteriaMatchArray = ["fruits"] //this is the input (currently processes only 1 item in list) and user can change or add more

    for (var i = 0; i < table[0].length; i++) {
        if (table[0][i].indexOf(CriteriaMatchArray[0]) == -1) {
            str.push("table[i][" + i + "]")
        } else {
            if (firstJoiningPosition == -1)
                firstJoiningPosition = i
            m.push("table[i][" + i + "]")
        }
    }

    str[firstJoiningPosition] = m.join("+ '#' +")
    evalstring = str.join(",")

    document.write('<pre>Given table   ' + JSON.stringify(table, null, 4) + '</pre>')

    var result = []

    for (var i = 0; i < table.length; i++) {
        eval("result.push(" + "[" + evalstring + "]" + ")")
    }

    document.write('<pre>Result after joining   ' + JSON.stringify(result, null, 4) + '</pre>')
</script>
</body>

</html>

【问题讨论】:

    标签: javascript arrays multidimensional-array


    【解决方案1】:

    我将首先定义需要组合在一起的列索引的范围。所以如果标准是“水果”,那么

    • 列索引 0 映射到一列(“Sl.no”不变)
    • 列索引 1 - 5 映射到列(对“水果”进行分组)
    • 列索引 6 映射到一列(蔬菜没有变化)
    • 列索引 7 映射到一列(蔬菜没有变化)

    所以范围——用 JavaScript 表示法——将是:

    [
        [0, 1],
        [1, 6],
        [6, 7],
        [7, 8]
    ]
    

    请注意,第二个索引是要包含的最后一列之后,很像slice 方法的工作原理。

    一旦您确定了这一点,就很容易迭代原始表格的行,并根据该信息将单元格组合在一起。

    这是一个实现:

    function collapse(table, criteria) {
        let head = table[0];
        let slices = [];
        for (let i = 0; i < head.length; i++) {
            let match = criteria.find(group => head[i].startsWith(group));
            let start = i;
            while (head[i+1]?.startsWith(match)) i++;
            slices.push([start, i+1]);
        }
        return table.map((row, i) =>
            slices.reduce((acc, [j, k]) => 
                acc.concat(i 
                    ? row.slice(j, k).filter(Boolean).join(", ")
                    : k > j+1 ? "Combined " + row[j].split(" ")[0] : row[j]
                )
            , [])
        );
    }
    
    let table = [
        ["Sl.no","fruits 1", "fruits 2", "fruits 3", "fruits 4", "fruits 5", "vegetables 1", "vegetables 2"],
        ["1","banana", "apple", "orange", "", "", "carrot", "cabbage"],
        ["2","watermelon", "apple", "orange", "", "", "beans", ""]
    ]
    
    // Demo run:
    let result = collapse(table, ["fruits"]);
    console.log(result);

    【讨论】:

      【解决方案2】:

      这是您想要的 95%。现在您只需要根据 isFruits 还是 isVegs 创建标题:

        const getInd = (headings, type) => headings.reduce((accum, item, ind) => {
          if (item.indexOf(type) != -1) {
            accum.push(ind)
          }
          return accum;
        }, [])
        
      const convert = (table, arrCriteria) => {
        const isFruits = arrCriteria.indexOf('fruits') != -1
        const isVegs = arrCriteria.indexOf('vegetables') != -1
        const headings = table[0];
        const arrFruitsInd = getInd(headings, 'fruits');
        const arrVegsInd = getInd(headings, 'vegetables')
        const extract = (arr, arrInd) => arr.filter((item, ind) => arrInd.indexOf(ind) != -1)
        const results = table.slice(1).map(arr => {
          const arrFruitsExtract = extract(arr, arrFruitsInd)
          const arrFruits = isFruits ? [arrFruitsExtract.filter(item => item).join('#')] : arrFruitsExtract
          const arrVegsExtract = extract(arr, arrVegsInd)
          const arrVegs = isVegs ? [arrVegsExtract.filter(item => item).join(', ')] : arrVegsExtract
          return [arr[0]].concat(arrFruits.concat(arrVegs))
        })
       return results
      }
      
      const table = [
              ["Sl.no","fruits 1", "fruits 2", "fruits 3", "fruits 4", "fruits 5", "vegetables 1", "vegetables 2"],
              ["1","banana", "apple", "orange", "", "", "carrot", "cabbage"],
              ["2","watermelon", "apple", "orange", "", "", "beans", ""]
          ]
      
      // console.log(convert(table, ['fruits']))
      console.log(convert(table, ['vegetables', 'fruits']))
      // console.log(convert(table, ['vegetables']))

      【讨论】:

      • 感谢史蒂夫,但我正在寻找更动态的解决方案。 indexOf 水果、蔬菜无法编码,它们将根据输入 CriteriaMatchArray 获取。我从您的解决方案中看到的是,它是硬编码的。有没有办法让它变得动态。我真的很感谢你。
      • 数据只是一个样本,真实的表由公司属性组成,如组织邮政编码,组织街道,组织电话,同样类别(水果和蔬菜)的数量是无限大的,所以这个解决方案不能被硬编码,我们需要让它动态确定类别
      • 我得到的是空结果 - i.stack.imgur.com/LBRAP.png
      • 提供另一个示例,以便我了解您对蔬菜/水果等索引的含义
      • 我的意思是 const arrFruitsInd = getInd(headings, 'fruits'); const arrVegsInd = getInd(headings, 'vegetables') 应该被移除,因为它们需要从 CriteriaMatchArray 动态生成
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-10
      • 1970-01-01
      • 2011-07-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多