如何将对象数组转换为在打字稿中具有动态键的单个对象

Posted

技术标签:

【中文标题】如何将对象数组转换为在打字稿中具有动态键的单个对象【英文标题】:How to convert array of objects to single object which has dynamic key in typescript 【发布时间】:2019-09-18 17:01:18 【问题描述】:

这个问题可能与常见问题类似,但这个问题有一些不同的方法。

在我的 Angular 7 应用程序中,我有以下 5 个数组,需要根据 id 使用动态键将其转换为下面的单个对象。


  "enabled-41": true,
  "enabled-42": true,
  "enabled-43": true,
  "enabled-44": true,
  "enabled-45": false,
  "abc-41": "some description 1",
  "abc-42": "some description 12",
  "abc-43": "some description 123",
  "abc-44": "some description 1234",
  "abc-45": null,
  "def-41": "some description 2",
  "def-42": "some description 23",
  "def-43": "some description 234",
  "def-44": "some description 2345",
  "def-45": null,
  "type-41": "def",
  "type-42": "abc",
  "type-43": "def",
  "type-44": "abc",
  "type-45": null,
  "weight-41": "25",
  "weight-42": "25",
  "weight-43": "25",
  "weight-44": "25",
  "weight-45": null

let arr = [
  
    "id": 41,
    "abc": "some description 1",
    "def": "some description 2",
    "type": "def",
    "Criteria": 
      "id": 5,
      "question": "follow-up",
      "definition": "definition content",
      "status": true
    ,
    "weight": 25,
    "enabled": true
  ,
  
    "id": 42,
    "abc": "some description 12",
    "def": "some description 23",
    "type": "abc",
    "Criteria": 
      "id": 1,
      "question": "coverage",
      "definition": "definition content",
      "status": true
    ,
    "weight": 25,
    "enabled": true
  ,
  
    "id": 43,
    "abc": "some description 123",
    "def": "some description 234",
    "type": "def",
    "Criteria": 
      "id": 4,
      "question": "Price",
      "definition": "definition content",
      "status": true
    ,
    "weight": 25,
    "enabled": true
  ,
  
    "id": 44,
    "abc": "some description 1234",
    "def": "some description 2345",
    "type": "abc",
    "Criteria": 
      "id": 3,
      "question": "Exchange",
      "definition": "definition content",
      "status": true
    ,
    "weight": 25,
    "enabled": true
  ,
  
    "id": 45,
    "Criteria": 
      "id": 2,
      "definition": "definition conent",
      "question": "Random",
      "status": true
    ,
    "type": null,
    "abc": null,
    "def": null,
    "weight": 0,
    "enabled": false
  
];

let result = arr.reduce(function(obj, item) 
    obj[item] = item.value;
    return obj;
, )

console.log(result);

我尝试过使用 reduce 函数,但无法根据动态键(用连字符连接 id)获得正确的方法来转换为上述格式的单个对象。

有人可以帮我解决这个问题吗?

【问题讨论】:

Criteria 对象呢?应该发生什么?它应该被丢弃吗? 是Criteria对象可以被丢弃,想得到同上的单个对象 【参考方案1】:

您的代码几乎就在那里。但是不能保证对象键的顺序。在reduce回调函数内部添加累加器中的键和对应的值。

在创建对象键时使用模板文字和方符号

let arr = [
    "id": 41,
    "abc": "some description 1",
    "def": "some description 2",
    "type": "def",
    "Criteria": 
      "id": 5,
      "question": "follow-up",
      "definition": "definition content",
      "status": true
    ,
    "weight": 25,
    "enabled": true
  ,
  
    "id": 42,
    "abc": "some description 12",
    "def": "some description 23",
    "type": "abc",
    "Criteria": 
      "id": 1,
      "question": "coverage",
      "definition": "definition content",
      "status": true
    ,
    "weight": 25,
    "enabled": true
  ,
  
    "id": 43,
    "abc": "some description 123",
    "def": "some description 234",
    "type": "def",
    "Criteria": 
      "id": 4,
      "question": "Price",
      "definition": "definition content",
      "status": true
    ,
    "weight": 25,
    "enabled": true
  ,
  
    "id": 44,
    "abc": "some description 1234",
    "def": "some description 2345",
    "type": "abc",
    "Criteria": 
      "id": 3,
      "question": "Exchange",
      "definition": "definition content",
      "status": true
    ,
    "weight": 25,
    "enabled": true
  ,
  
    "id": 45,
    "Criteria": 
      "id": 2,
      "definition": "definition conent",
      "question": "Random",
      "status": true
    ,
    "type": null,
    "abc": null,
    "def": null,
    "weight": 0,
    "enabled": false
  
];

let result = arr.reduce(function(obj, item) 
  obj[`enabled-$item.id`] = item.enabled;
  obj[`abc-$item.id`] = item.abc;
  obj[`def-$item.id`] = item.def;
  obj[`type-$item.id`] = item.type;
  obj[`weight-$item.id`] = item.weight;
  return obj;
, );
console.log(result)

【讨论】:

谢谢,对象键顺序有可能吗? @UI_Dev 希望此链接***.com/questions/5525795/… 对您有所帮助 @UI_Dev 有人做过【参考方案2】:

您可以将reduceObject.keys 一起使用,并将您希望排除的所有键放在一个数组中并检查:

let arr = ["id":41,"abc":"some description 1","def":"some description 2","type":"def","Criteria":"id":5,"question":"follow-up","definition":"definition content","status":true,"weight":25,"enabled":true,"id":42,"abc":"some description 12","def":"some description 23","type":"abc","Criteria":"id":1,"question":"coverage","definition":"definition content","status":true,"weight":25,"enabled":true,"id":43,"abc":"some description 123","def":"some description 234","type":"def","Criteria":"id":4,"question":"Price","definition":"definition content","status":true,"weight":25,"enabled":true,"id":44,"abc":"some description 1234","def":"some description 2345","type":"abc","Criteria":"id":3,"question":"Exchange","definition":"definition content","status":true,"weight":25,"enabled":true,"id":45,"Criteria":"id":2,"definition":"definition conent","question":"Random","status":true,"type":null,"abc":null,"def":null,"weight":0,"enabled":false];

let exclude = ["id", "Criteria"];

let result = arr.reduce((acc, curr) => 
  let id = curr.id;
  Object.entries(curr).forEach(([k, v]) => 
    if (!exclude.includes(k)) acc[`$k-$id`] = v;
  );
  return acc;
, );

console.log(result);

【讨论】:

【参考方案3】:

假设您要排除所有值为 object 的属性,也许您可​​以采用这个通用的想法,即使用 Object.entries() 遍历内部对象和一些 destructuring 特征。

let arr=["id":41,"abc":"some description 1","def":"some description 2","type":"def","Criteria":"id":5,"question":"follow-up","definition":"definition content","status":true,"weight":25,"enabled":true,"id":42,"abc":"some description 12","def":"some description 23","type":"abc","Criteria":"id":1,"question":"coverage","definition":"definition content","status":true,"weight":25,"enabled":true,"id":43,"abc":"some description 123","def":"some description 234","type":"def","Criteria":"id":4,"question":"Price","definition":"definition content","status":true,"weight":25,"enabled":true,"id":44,"abc":"some description 1234","def":"some description 2345","type":"abc","Criteria":"id":3,"question":"Exchange","definition":"definition content","status":true,"weight":25,"enabled":true,"id":45,"Criteria":"id":2,"definition":"definition conent","question":"Random","status":true,"type":null,"abc":null,"def":null,"weight":0,"enabled":false];

let result = arr.reduce((obj, id, ...rest) =>

    Object.entries(rest).forEach(([k, v]) =>
    
        if (Object(v) !== v) obj[`$k-$id`] = v;
    );

    return obj;
, );

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

【讨论】:

【参考方案4】:

哦,伙计……我刚刚被打败了。这是我的解决方案。

let arr= [] // hold the final object array
let keys = [] // temp item to hold the value of each key

    // iterate over each key
    Object.keys(input).forEach((key) =>   
    let pair = key.split('-') // split the key into the real key and the index

    // if the index isn't in the array, push it there (this keeps the same order)
    if (keys.indexOf(pair[1])===-1)  
        keys.push(pair[1])
    

    // use object.assign to add the keys to the existing object in the right place in the array. 
    arr[keys.indexOf(pair[1])] = Object.assign(, arr[keys.indexOf(pair[1])], [pair[0]]: input[key],  id: pair[1] ) 

)

【讨论】:

【参考方案5】:

function getFilteredData(arr) 
  const result = ;
  arr.forEach(item => 
    const  id, Criteria, ...rest  = item;
    Object.entries(rest).map(([key, value]) => 
      result[`$key-$id`] = value;
    );
  );
  return result;


let arr = [
  
    id: 41,
    abc: 'some description 1',
    def: 'some description 2',
    type: 'def',
    Criteria: 
      id: 5,
      question: 'follow-up',
      definition: 'definition content',
      status: true
    ,
    weight: 25,
    enabled: true
  ,
  
    id: 42,
    abc: 'some description 12',
    def: 'some description 23',
    type: 'abc',
    Criteria: 
      id: 1,
      question: 'coverage',
      definition: 'definition content',
      status: true
    ,
    weight: 25,
    enabled: true
  ,
  
    id: 43,
    abc: 'some description 123',
    def: 'some description 234',
    type: 'def',
    Criteria: 
      id: 4,
      question: 'Price',
      definition: 'definition content',
      status: true
    ,
    weight: 25,
    enabled: true
  ,
  
    id: 44,
    abc: 'some description 1234',
    def: 'some description 2345',
    type: 'abc',
    Criteria: 
      id: 3,
      question: 'Exchange',
      definition: 'definition content',
      status: true
    ,
    weight: 25,
    enabled: true
  ,
  
    id: 45,
    Criteria: 
      id: 2,
      definition: 'definition conent',
      question: 'Random',
      status: true
    ,
    type: null,
    abc: null,
    def: null,
    weight: 0,
    enabled: false
  
];

console.log(getFilteredData(arr));

【讨论】:

以上是关于如何将对象数组转换为在打字稿中具有动态键的单个对象的主要内容,如果未能解决你的问题,请参考以下文章

打字稿中具有联合类型键的松散类型对象

如何将这些对象转换为打字稿中的数组

如何在打字稿中使用可能的字符串和数字索引确定对象的类型?

如何在打字稿中过滤对象数组

如何使用打字稿中的查找来推断类型化的 mapValues?

如何将方法的泛型类型限制为打字稿中的对象?