【问题标题】:How to "transpose" Objects in TypeScript如何在 TypeScript 中“转置”对象
【发布时间】:2018-11-19 18:37:56
【问题描述】:

有没有办法很好地从对象转换:

Key_1 : {Head_1 : "val_11", Head_2 : "val_21", Head_3 : "val_31"}
Key_2 : {Head_1 : "val_12", Head_2 : "val_22", Head_3 : "val_32"}
Key_3 : {Head_1 : "val_13", Head_2 : "val_23", Head_3 : "val_33"}

到:

Head_1 : {Key_1 : "val_11", Key_2 : "val_12", Key_3: "val_13"}
Head_2 : {Key_1 : "val_21", Key_2 : "val_22", Key_3: "val_23"}
Head_3 : {Key_1 : "val_31", Key_2 : "val_32", Key_3: "val_33"}

在 TypeScript 中?

非常感谢!

【问题讨论】:

  • 到目前为止你有什么尝试?

标签: javascript typescript javascript-objects transpose


【解决方案1】:

你可以使用下面的“for..of”和“Object.entries”来转置

顺便说一句,写下你的方法/你在 OP 中尝试过什么总是更好,这样其他用户就可以看到你的前进方向

var obj = {
  Key_1 : {Head_1 : "val_11", Head_2 : "val_21", Head_3 : "val_31"},
  Key_2 : {Head_1 : "val_12", Head_2 : "val_22", Head_3 : "val_32"},
  Key_3 : {Head_1 : "val_13", Head_2 : "val_23", Head_3 : "val_33"}
}

function transpose(obj) {
  let newObj = {}
  for(let [key, value] of Object.entries(obj)) {
    for(let [k, v] of Object.entries(value)) { 
       newObj[k] = newObj[k] || {}
       newObj[k][key] = v
    }
  }
  return newObj
}

console.log(transpose(obj))

【讨论】:

  • 为什么将for … offorEach 样式循环混合使用?那看起来很可怕。使用正确的for … of 循环,不要滥用逗号运算符。
  • 完成@Bergi。我看到你在使用for..of 时的一致性点......我觉得这对你来说很可怕......只是想了解'不要滥用逗号运算符'..我在哪里滥用它,只是为了我的理解.
  • @NitishNarang 感谢您的编辑。我对逗号操作符的问题是 ([k, v]) => ( newObj[k] = newObj[k] || {} , newObj[k][key] = v ) 可以写得更简洁(而且一样短)([k, v]) => { newObj[k] = newObj[k] || {} ; newObj[k][key] = v }
  • 哦!我明白了。谢谢你的指点..这只是我在编码时采用逗号优先方法的方式......但会确保代码看起来更清晰且易于理解。 :)
【解决方案2】:

其他答案很好,但我没有看到任何处理特定于 TypeScript 的类型系统的东西。以下类型定义和签名应该允许编译器理解转置对象的类型(假设 TS2.8+):

type AllKeys<T> = T extends any ? keyof T : never;
type RelevantKeys<T, K extends keyof T[keyof T]> = {
    [L in keyof T]: K extends keyof T[L] ? L : never
}[keyof T];

type Transpose<T> = {
    [K in AllKeys<T[keyof T]>]: {
        [L in RelevantKeys<T, K>]: T[L][K]
    }
};    

function transpose<T extends object & Record<keyof T, object>>(t: T): Transpose<T>;
// one possible implementation, use your favorite from above
function transpose(t: { [k: string]: { [l: string]: any } }) {
    const ret = {} as { [l: string]: { [k: string]: any } };
    Object.keys(t).forEach(k =>
        Object.keys(t[k]).forEach(l => {
            if (!(l in ret)) ret[l] = {};
            ret[l][k] = t[k][l];
        })
    );
    return ret;
}

观察类型:

var obj = {
  Key_1: { Head_1: "val_11", Head_2: "val_21", Head_3: "val_31" },
  Key_2: { Head_1: "val_12", Head_2: "val_22", Head_3: "val_32" },
  Key_3: { Head_1: "val_13", Head_2: "val_23", Head_3: "val_33" }
}
const transposed = transpose(obj);

// the following are compile-time IntelliSense and/or error messages
transposed.Head_1; // {Key_1: string, Key_2: string, Key_3: string};
transposed.Haed_2; // error, property Haed2 does not exist
transposed.Head_3.Key_2; // string

const x = { a: { b: 1, c: true }, d: { e: "hey", f: undefined } };
const y = transpose(x);
y.e.d; // string
y.e.a; // error, property 'a' does not exist on {d: string}
y.b.a; // number
y.b.d; // error, property 'd' does not exist on {a: number}

希望有帮助!

【讨论】:

    【解决方案3】:

    另一种方法是使用Array.prototype.reduce:

    const input = {
      Key_1: {Head_1: 'val_11', Head_2: 'val_21', Head_3: 'val_31'},
      Key_2: {Head_1: 'val_12', Head_2: 'val_22', Head_3: 'val_32'},
      Key_3: {Head_1: 'val_13', Head_2: 'val_23', Head_3: 'val_33'},
    };
    
    const output = Object.entries(input).reduce((acc, [key, keyVal]) => {
      Object.entries(keyVal).forEach(([head, headVal]) => {
        acc[head] = acc[head] || {};
        acc[head][key] = headVal;
      });
      return acc;
    }, {});
    
    console.log(output);

    如果需要兼容性,请不要忘记转译和添加 polyfill。

    【讨论】:

      猜你喜欢
      • 2020-07-16
      • 1970-01-01
      • 2021-03-04
      • 2021-11-20
      • 2021-06-20
      • 2016-09-14
      • 1970-01-01
      • 2017-02-26
      • 1970-01-01
      相关资源
      最近更新 更多