Как «транспонировать» объекты в TypeScript - PullRequest
0 голосов
/ 19 ноября 2018

Есть ли способ красиво конвертировать из объекта:

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?

Большое спасибо!

Ответы [ 3 ]

0 голосов
/ 19 ноября 2018

Другой подход заключается в использовании 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);

Не забудьте перенести и добавить полифилы, если это необходимо для совместимости.

0 голосов
/ 19 ноября 2018

Другие ответы великолепны, но я не вижу ничего, что касалось системы типов, специфичной для 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}

Надеюсь, это поможет!

0 голосов
/ 19 ноября 2018

Вы можете использовать "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))
...