Ищете способ в Javascript для преобразования массива стиля столбца с дубликатами данных в объект - PullRequest
0 голосов
/ 19 декабря 2018

Я пытаюсь преобразовать массив, похожий на приведенный ниже, в структуру объекта под массивом.

Я пробовал несколько вещей, которые я также перечислю ниже.Но я чувствую, что поступаю неправильно.И хотел бы помочь с этим.

var array = [
  ["plan_a", "tester_a", "product", "foo", "blocked", "5"],
  ["plan_a", "tester_a", "product", "foo", "passed", "10"],
  ["plan_a", "tester_a", "subproduct", "client", "passed", "15"],
  ["plan_a", "tester_b", "product", "bar", "blocked", "5"],
  ["plan_a", "tester_b", "product", "bar", "passed", "10"],
  ["plan_a", "tester_b", "subproduct", "server", "failed", "5"],
  ["plan_a", "tester_b", "subproduct", "server", "passed", "5"],
  ["plan_a", "tester_c", "product", "foo", "failed", "5"]
];

var object = {
  plan_a: {
    tester_a: {
      product: {
        product: "foo",
        blocked: "5",
        passed: "10"
      },
      subproduct: {
        subproduct: "client",
        passed: "15"
      }
    },
    tester_b: {
      product: {
        product: "bar",
        blocked: "5",
        passed: "10"
      },
      subproduct: {
        subproduct: "server",
        failed: "5",
        passed: "5"
      }
    },
    tester_c: {
      product: {
        product: "foo",
        failed: "5"
      }
    }
  }
};

Я пробовал это:

var object = {}
var combining_plans =[]
var first_row = arr[0][0];

for (var i = 0; i < arr.length; i++) {
    if (arr[i][0] == first_row) {
        object[arr[i][0]] = [];
        arr[i].shift();
        combining_plans.push(arr[i]);
    }
}

object[first_row] = combining_plans;

Это проверяет первый столбец на то же самое, если то же самое, что и первый элемент превращает его впервый ключ объекта, а затем добавляет значения как все остальные элементы массива.

Я думал о том, чтобы делать это снова и снова для каждого столбца, но я чувствую, что это может не сработать, и естьболее элегантный способ, чем сделать это.

Ответы [ 3 ]

0 голосов
/ 19 декабря 2018

Вы можете использовать Array.reduce() и Array.forEach() для создания объекта:

const array = [
  ["plan_a", "tester_a", "product"   ,"foo"   ,"blocked", "5"   ],
  ["plan_a", "tester_a", "product"   ,"foo"   ,"passed" , "10"  ],
  ["plan_a", "tester_a", "subproduct","client","passed" , "15"  ],
  ["plan_a", "tester_b", "product"   ,"bar"   ,"blocked", "5"   ],
  ["plan_a", "tester_b", "product"   ,"bar"   ,"passed" , "10"  ],
  ["plan_a", "tester_b", "subproduct","server","failed" , "5"  ],
  ["plan_a", "tester_b", "subproduct","server","passed" , "5"  ],
  ["plan_a", "tester_c", "product"   ,"foo"   ,"failed" , "5"  ],
];

const result = array.reduce((r, row) => {
  const val = row[row.length - 1];
  const path = row.slice(0, -1);
  let current = r;
  
  path.forEach((p, i) => {
    if(i === 4) current[p] = val;
    else if(i === 3) current[path[2]] = p;
    else {
      current[p] = current[p] || {};
      current = current[p];
    }
  });
  

  return r;
}, {});

console.log(result);
0 голосов
/ 19 декабря 2018

Альтернативой предоставленным ответам будет сопоставление + уменьшение.

Вы можете отобразить свой массив в виде кусков объектов, похожих на результаты, которые вы можете глубоко объединить после:

const array = [
  ["plan_a", "tester_a", "product", "foo", "blocked", "5"],
  ["plan_a", "tester_a", "product", "foo", "passed", "10"],
  ["plan_a", "tester_a", "subproduct", "client", "passed", "15"],
  ["plan_a", "tester_b", "product", "bar", "blocked", "5"],
  ["plan_a", "tester_b", "product", "bar", "passed", "10"],
  ["plan_a", "tester_b", "subproduct", "server", "failed", "5"],
  ["plan_a", "tester_b", "subproduct", "server", "passed", "5"],
  ["plan_a", "tester_c", "product", "foo", "failed", "5"]
];


const result = array.map(mapIntoResultChunkShape).reduce(merge);
//                                                       ^^^^^ comes from lodash

function mapIntoResultChunkShape([
  product,
  tester,
  categoryName,
  categoryValue,
  resultName,
  resultValue
]) {
  return {
    [product]: {
      [tester]: {
        [categoryName]: {
          [categoryName]: categoryValue,
          [resultName]: resultValue
        }
      }
    }
  };
}

console.log(JSON.stringify(result, null, 2));
<script src="https://unpkg.com/lodash.merge@4.6.1/index.js"></script>

Основным преимуществом этого подхода является то, что он разделяет проблемы.Чтобы настроить этот код для любого другого преобразования массива-> объекта, все, что вам нужно сделать, это изменить способ отображения элемента массива в форму результата, то есть функцию mapIntoResultChunkShape.

Вы также можете создать свойсобственная функция слияния, специализированная для вашего прецедента, которая может нести больше накладных расходов, чем использование более обобщенной библиотеки, созданной для обработки всех случаев:

const array = [
  ["plan_a", "tester_a", "product", "foo", "blocked", "5"],
  ["plan_a", "tester_a", "product", "foo", "passed", "10"],
  ["plan_a", "tester_a", "subproduct", "client", "passed", "15"],
  ["plan_a", "tester_b", "product", "bar", "blocked", "5"],
  ["plan_a", "tester_b", "product", "bar", "passed", "10"],
  ["plan_a", "tester_b", "subproduct", "server", "failed", "5"],
  ["plan_a", "tester_b", "subproduct", "server", "passed", "5"],
  ["plan_a", "tester_c", "product", "foo", "failed", "5"]
];

const result = array.map(mapIntoResultChunkShape).reduce(mergeResultChunkShapes);

function mapIntoResultChunkShape([
  product,
  tester,
  categoryName,
  categoryValue,
  resultName,
  resultValue
]) {
  return {
    [product]: {
      [tester]: {
        [categoryName]: {
          [categoryName]: categoryValue,
          [resultName]: resultValue
        }
      }
    }
  };
}

function mergeResultChunkShapes(item1, item2) {
  if (
    item1 === null ||
    typeof item1 !== "object" ||
    (item2 === null || typeof item2 !== "object")
  ) {
    return item1 || item2;
  }

  const uniqueKeys = new Set(Object.keys(item1).concat(Object.keys(item2)));

  return Array.from(uniqueKeys).reduce((res, key) => {
    return Object.assign(res, {
      [key]: mergeResultChunkShapes(item1[key], item2[key])
    });
  }, {});
}

console.log(JSON.stringify(result, null, 2));
0 голосов
/ 19 декабря 2018

const array = [
	["plan_a", "tester_a", "product"   ,"foo"   ,"blocked", "5"  ],
	["plan_a", "tester_a", "product"   ,"foo"   ,"passed" , "10" ],
	["plan_a", "tester_a", "subproduct","client","passed" , "15" ],
	["plan_a", "tester_b", "product"   ,"bar"   ,"blocked", "5"  ],
	["plan_a", "tester_b", "product"   ,"bar"   ,"passed" , "10" ],
	["plan_a", "tester_b", "subproduct","server","failed" , "5"  ],
	["plan_a", "tester_b", "subproduct","server","passed" , "5"  ],
	["plan_a", "tester_c", "product"   ,"foo"   ,"failed" , "5"  ],
];
const result = {};
array.forEach((item) => {
	const [plan, tester, type, name, key, value] = item;
	if(!result[plan]) {
		result[plan] = {};
	}
	if(!result[plan][tester]) {
		result[plan][tester] = {};
	}
	if(!result[plan][tester][type]) {
		result[plan][tester][type] = {[type]: name};
	}
	Object.assign(result[plan][tester][type], {[key]: value});
});
console.log(result);
...