【问题标题】:JavaScript - how to build build an hierarchy object from a CSV fileJavaScript - 如何从 CSV 文件构建层次结构对象
【发布时间】:2021-11-28 01:05:46
【问题描述】:

我在下面有一个 CSV 文件,我想用它构建一个 javascript 对象。

我正在尝试从“类别”列中提取元素并创建一个层次结构对象,然后将信息放在对象最低级别的“颜色”列下。

目标:

以下是迄今为止我尝试从 CSV 中提取信息的内容,以及确定如何从这里开始的内容。什么是最好和最有效的?

let csv = `id, category, year, color, price \n
01, SUV > AWD > Sport > Benz, 2017, blue, $20 \n
02, SUV > FWD > Family > Benz, 2018, black, $20 \n
03, Sedan > AWD > BNW, 2017, white, $30 \n
04, SUV > AWD > Sport > BNW, 2012, red, $30 \n
05, Seden > RWD > Toyota, 2019, white, $30`

function extractCSV(csv){
    let object = {}
    let data = csv.split('\n')

    for(let i = 1; i < data.length; i++){
        let subData = data[i].split(',')
        for(let j = 1; j < subData.length; j++){
            let header = subData[j].split(">")

            if(header.length > 1){
                for(let k = 0; k < header.length; k++){
                    
                }
            } 
        }
    }
    return object
}

提前致谢

【问题讨论】:

    标签: javascript csv object binary-tree


    【解决方案1】:

    首先,两个答案中的“更好”。

    您会看到它遵循与您开始时大致相同的流程,但是,我选择将所有解析放在前面,放入一些中间对象中。这使得后面的代码可以专注于构建我们的树。

    let csv = `id, category, year, color, price \n
    01, SUV > AWD > Sport > Benz, 2017, blue, $20 \n
    02, SUV > FWD > Family > Benz, 2018, black, $20 \n
    03, Sedan > AWD > BNW, 2017, white, $30 \n
    04, SUV > AWD > Sport > BNW, 2012, red, $30 \n
    05, Sedan > RWD > Toyota, 2019, white, $30`;
    
    function parseCsv(csv) {
      let object = {};
    
      // Parse/Sanitize all the data up front
      const rows = csv
        .split("\n")
        .filter((row, index) => index && row)
        .map((row) => {
          const columns = row.split(",");
          return {
            headers: columns[1].split(">").map((p) => p.trim()),
            color: columns[3].trim()
          };
        });
    
      // Then spin through the rows
      for (const row of rows) {
        let currentObj = object;
    
        // Then spin through the headers
        for (let hi = 0; hi < row.headers.length; ++hi) {
          const header = row.headers[hi];
    
          // If it is the last header, assign the color to it
          if (hi === row.headers.length - 1) {
            currentObj[header] = row.color;
            break;
          }
    
          // Else we need to get or set another object level
          currentObj = currentObj[header] = currentObj[header] ?? {};
        }
      }
    
      return object;
    }
    
    console.log(parseCsv(csv));
    

    其次,我在这里采取了另一种方法。我在递归解决方案中发现了一些优雅。虽然,它可能更难阅读,很可能会使用更多内存,并且速度较慢,尤其是文档/标题深度增加时。但我把它包括在内是为了好玩!

    let csv = `id, category, year, color, price \n
    01, SUV > AWD > Sport > Benz, 2017, blue, $20 \n
    02, SUV > FWD > Family > Benz, 2018, black, $20 \n
    03, Sedan > AWD > BNW, 2017, white, $30 \n
    04, SUV > AWD > Sport > BNW, 2012, red, $30 \n
    05, Sedan > RWD > Toyota, 2019, white, $30`;
    
    const parseCsv = (csv) => {
      const result = {};
    
      // Parse/Sanitize all the data up front
      const rows = csv
        .split("\n")
        .filter((row, index) => index && row)
        .map((row) => {
          const columns = row.split(",");
          return {
            headers: columns[1].split('>').map(p => p.trim()),
            color: columns[3].trim()
          };
        });
    
      // The recursive function, takes in
      // {target} the current object in the tree we're  at
      // {headers} the remaining headers to step through
      // {color} the color to assign to the last header
      const handleRow = (target, headers, color) => {
        // Last header, so just assign the color to it
        if (headers.length === 1) {
          target[headers[0]] = color;
          return;
        }
    
        // Else we need to get or set another object level
        const newTarget = (target[headers[0]] = target[headers[0]] ?? {});
        // And call into the next level with it and the remaining headers
        handleRow(newTarget, headers.slice(1), color);
      };
    
      for (const row of rows) {
        handleRow(result, row.headers, row.color);
      }
    
      return result;
    };
    
    console.log(parseCsv(csv));
    

    【讨论】:

    • 非常感谢您提供上面的代码,它完全实现了我想要的。如果我可能会问一些问题,在您的代码中,您从未接触过“object”而是使用“currentObj”,但最后“object”添加了所有信息,这背后的原因是什么?
    • 在处理每一行的最开始,我们将currentObj 重置为对象,然后我们通过该引用对其进行修改。至于拥有currentObj 背后的原因,它只是一个变量,用于跟踪我们正在处理的当前对象,如行走/生长树。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-26
    相关资源
    最近更新 更多