【问题标题】:Javascript parse excel file and create cartesian productJavascript解析excel文件并创建笛卡尔积
【发布时间】:2020-10-09 08:02:53
【问题描述】:

我有一个包含两张工作表的 excel 文件。一个是 source 表,其中包含 ID 列表。第二张表是包含三列的数据。

我正在尝试解析此文档并从两张表中创建一个笛卡尔积。 对于source 工作表上的每个 ID,它都需要与data 工作表上的每一行相结合。

示例:

表 1(来源):

ABC
DEF
GHI

表 2(数据):

Bob, 20, Arizona
James, 30, California
Sam, 40, Florida

预期输出:

Bob, 20, Arizona, ABC
James, 30, California, ABC
Sam, 40, Florida, ABC

Bob, 20, Arizona, DEF
James, 30, California, DEF
Sam, 40, Florida, DEF

Bob, 20, Arizona, GHI
James, 30, California, GHI
Sam, 40, Florida, GHI

我正在使用nodejs 来解析这个 xlsx 文件并遍历工作表。我得到两个数组,每个数组都有正确的数据,如下所示。

[
  { SourceId: 'ABC' },
  { SourceId: 'DEF' },
  { SourceId: 'GHI' }
]
[
  { Name: 'Bob', Age: 20, Location: 'Arizona' },
  { Name: 'James', Age: 30, Location: 'California' },
  { Name: 'Sam', Age: 40, Location: 'Florida' }
]

我现在尝试将数据中的每一行映射到源中的每一行的两者结合起来。在我的示例中,有 3 行数据和 3 个源 ID。这可能会产生 9 个结果的输出。

如果这两个都是数组,那将是直截了当的,但我无法弄清楚如何将它们添加到数据对象中。

代码:

var XLSX = require("xlsx");
var workbook = XLSX.readFile("data.xlsx");
var sheet_name_list = workbook.SheetNames;

sheet_name_list.forEach(function (y) {
  var worksheet = workbook.Sheets[y];
  var worksheetName = y;
  var headers = {};
  var data = [];
  var primarySet = [];

  for (z in worksheet) {
    if (z[0] === "!") continue;

    //parse out the column, row, and value
    var col = z.substring(0, 1);
    var row = parseInt(z.substring(1));
    var value = worksheet[z].v;

    //store header names
    if (row == 1) {
      headers[col] = value;
      continue;
    }

    if (worksheetName == "Source") {
      if (!primarySet[[row]]) {
        primarySet[row] = {};
      }
      primarySet[row][headers[col]] = value;
    }

    if (!data[row]) {
      data[row] = {};
    }
    data[row][headers[col]] = value;

  }
  //drop those first two rows which are empty
  data.shift();
  data.shift();
  console.log(data);

  /* Expected Output

  [
    { Name: 'Bob', Age: 20, Location: 'Arizona', SourceId: 'ABC' },
    { Name: 'James', Age: 30, Location: 'California', SourceId: 'ABC' },
    { Name: 'Sam', Age: 40, Location: 'Florida', SourceId: 'ABC' },

    { Name: 'Bob', Age: 20, Location: 'Arizona', SourceId: 'DEF' },
    { Name: 'James', Age: 30, Location: 'California', SourceId: 'DEF' },
    { Name: 'Sam', Age: 40, Location: 'Florida', SourceId: 'DEF' },

    { Name: 'Bob', Age: 20, Location: 'Arizona', SourceId: 'GHI' },
    { Name: 'James', Age: 30, Location: 'California', SourceId: 'GHI' },
    { Name: 'Sam', Age: 40, Location: 'Florida', SourceId: 'GHI' },

]

   */

});

有没有一种很好的方法来处理这个问题,我可以基本上将源合并到数据n 次?

【问题讨论】:

  • 你试过flatMap吗?

标签: javascript node.js cartesian-product


【解决方案1】:

如何使用flatMap 来获得预期的输出:

var arr1 = [ { SourceId: 'ABC' }, { SourceId: 'DEF' }, { SourceId: 'GHI' }];
var arr2 = [ { Name: 'Bob', Age: 20, Location: 'Arizona' }, { Name: 'James', Age: 30, Location: 'California' }, { Name: 'Sam', Age: 40, Location: 'Florida' }];

var result = arr1.flatMap(({SourceId},i)=>arr2.map(val=>({...val, SourceId})));

console.log(result)

【讨论】:

  • 谢谢,我认为这行得通。只是好奇,SourceId 在结果中可以是动态的吗?即它可以使用来自arr1 的属性键,这样如果array1 中的列名最终是SrcId,flatMap 和map 仍然可以工作,因为它会动态使用键名而不是硬编码它?
  • @SBB 我已经在此处解构了对象(SourceId),所以每次如果这错过了数组中该名称的键,它将是undefined。如果一致,它将正常工作。
  • 完全理解,只是想办法让它动态化,这样列名可以由用户定义,而代码不是在寻找特定的东西。不过,与这个问题无关,我会调查一下。谢谢!
猜你喜欢
  • 2014-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-28
  • 2015-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多