将 excel 二维数组转换为包含列名的嵌套属性对象

Posted

技术标签:

【中文标题】将 excel 二维数组转换为包含列名的嵌套属性对象【英文标题】:Transform excel 2D array into nested properties object with column names included 【发布时间】:2020-03-27 07:49:05 【问题描述】:

我有一个 Excel 文件如下:

[["Country", "City", "Zip"], ["CNTR1", "CT1", 101], ["CNTR1", "CT2", 102], ["CNTR2", "CT3", 103]]

以上是Excel 4行的二维数组解释。我想从上面得到以下对象:


    level1: "Country",
    items: [
        "CNTR1": 
            level2: "City",
            items: [
                "CT1": 
                    level3: "Zip",
                    items: [
                        "101"
                    ]
                
            , 
                "CT2": 
                    level3: "Zip",
                    items: [
                        "102"
                    ]
                
            ]
        
    , 
        "CNTR2": 
            level2: "City",
            items: [
                "CT3": 
                    level3: "Zip",
                    items: [
                        "103"
                    ]
                
            ]
        
    ]

主要目的是有一个层次结构,因为上面的 Excel 应该有一个从左到右的依赖关系,因为这些值将在依赖下拉列表中使用(所以如果我们有国家“CNTR1”,所有城市和邮政编码应该是其对象的一部分,因为在国家下拉列表中选择“CNTR1”后,只有 CT1 和 CT2 应该显示在城市下拉列表中,以此类推邮政编码),并且基于这种依赖关系,我们应该有每个的子值嵌套级别。此外,上述内容不应仅限于三层深度,因此应该使用 reducers/recursive 解决方案。

如果有人有更好的对象模式解决方案,因为我认为以上内容既符合依赖下拉列表的目的,同时也检索列名,请随时分享。下拉列表将是动态的,依赖于从左到右的列,并且值基于相同的“更高”层次结构值。

希望它足够清楚。

到目前为止,我有:

items.map(row => row.reduceRight((value, key) => ([key]: value))).reduce((acc, value) => (Object.assign(acc, value)))

但是这个只是给出类型的结果:


  "CNTR1": 
    "CT2": 102
  ,
  "CNTR2": 
    "CT3": 103
  

(忽略嵌套属性数据的丢失,因为合并不深)列的名称不包括在内,对于指定的目的,数据结构似乎有点差。

谢谢

【问题讨论】:

【参考方案1】:

您可以通过减少嵌套数组来减少数组并构建所需的结构。并重新调整内部 items 数组。

var data = [["Country", "City", "Zip"], ["CNTR1", "CT1", 101], ["CNTR1", "CT2", 102], ["CNTR2", "CT3", 103]],
    result = data.reduce((r, [...a], i,  [0]: header ) => 
        var last = a.pop();
        if (i === 1) r =  level1: header[0], items: [] ;
        a.reduce((items, k, i) => 
            var temp = items.find(q => k in q);
            if (!temp) items.push(temp =  [k]: ['level' + (i + 2)]: header[i + 1], items: []  );
            return temp[k].items;
        , r.items).push(last);
        return r;
    );

console.log(result);
.as-console-wrapper  max-height: 100% !important; top: 0; 

【讨论】:

是的,谢谢,就是这样。您认为这种结构是否适合指定的目的?我在想level 键中的索引可能是多余的,因为它可以在迭代期间轻松检索,但除此之外,我认为它有助于深入遍历不需要任何查询的依赖元素在同一级别。 我不知道 excel 如何为此目的工作。但如果这是你需要的结构,那就去吧。 (我个人会选择一些不改变属性的东西,比如level,并使用一种无​​需检索具有更扁平数据结构的密钥的格式。) 嗯,Excel 更像是一个数据提供者,但归根结底,问题开头提供的数组是检索到的数据。目的是派生从左到右的父子关系,并创建一种树,同时还保持关卡的名称。你能提供一个你提到的平面结构的简单对象吗?谢谢 可能是这样的: level: 1, value: "Country", items: [ level: 2, value: "City", key: "CNTR1", items: [ level: 3, key: "CT1", value: "Zip", items: [101] , level: 3, key: "CT2", value: "Zip", items: [102] ] , level: 2, key: "CNTR2", value: "City", items: [ level: 3, key: "CT3", value: "Zip", items: [103] ] ] 我明白了,所以与其将键作为属性,不如将它放在对象内部,并且它更有条理。谢谢。【参考方案2】:

您可以使用reduce 方法创建类似的结构,方法是从数组中的第一个元素切片,然后从数组中的第一个元素获取当前级别。

const data = [["Country", "City", "Zip"], ["CNTR1", "CT1", 101], ["CNTR1", "CT2", 102], ["CNTR2", "CT3", 103]]

function build(data, level) 
  return data.slice(1).reduce((r, a) => 
    a.reduce((ac, e, i, arr) => 
      ac.level = data[0][i]
      if (arr[i + 1]) ac[e] = (ac[e] || )
      else ac.value = e;
      return ac[e];
    , r)
    return r
  , )


const result = build(data);
console.log(result)

【讨论】:

以上将覆盖最后一级键。用这个数组检查它:const data = [["Country", "City", "Zip"], ["CNTR1", "CT1", 101], ["CNTR1", "CT1", 102], ["CNTR2", "CT3", 103]] 结果将是: "level": "Country", "CNTR1": "level": "City", "CT1": "level": "Zip", "value": 102 , "CNTR2": "level": "City", "CT3": "level": "Zip", "value": 103 101 邮政编码将丢失。

以上是关于将 excel 二维数组转换为包含列名的嵌套属性对象的主要内容,如果未能解决你的问题,请参考以下文章

将 ArrayList 转换为包含不同长度数组的二维数组

如何将嵌套数组对转换为数组中的对象

PHP二维数组转换成HTML

无法使用 Gson 将包含嵌套 json 数组的 json 转换为等效的 JAVA 类

csv转换obj

如何将 c# 二维数组转换为 JSON 对象?