概述
我使用Microsoft OData Query Builder library生成嵌套表,但我需要平面表。为实现这一目标,我有两种可能的解决方案,
我尝试了第一种方法并坚持下去 - https://jsfiddle.net/e14oL103/10/ 我期待输出就像这样,
ID Name Products.0.ID
999 Meat 17987
999 Meat 17988
999 Meat 17989
999 Meat 17990
第二种方法的问题
例如(我有什么) ,如果我有这样的表,
http://image.prntscr.com/image/1fedddfc3cf142c5963a23a94c746612.png
我想要的东西 - 仅适用于图片中的第一个tr,其余部分将遵循相同的逻辑
MainTable.Name Product.ID Product.Name Product.Description ProductDetail.Details
Food 0 Bread Whole gain bread
Food 1 Milk Low Fat Milk Details of product 1
我的情景比上面更加动态和复杂,但我不知道从哪里开始。
为什么我认为它不重复
我不需要扁平阵列,我无法找到正确的单词,之前是#34;笛卡尔积"。我可以使用underscore.js来压缩数组,但这不是我想要的,我想将父数组的元素与子数组结合起来。
答案 0 :(得分:2)
更改了您的代码段。对不起凌乱的代码。希望能帮助到你。 (js fidle here)
/**
* @param {array} array - The data to be converted into flat view
* @param {array} schema - Accumulates names and represents names of the columns
* @param {array} record - Array with values accumulated so far with indexes corresponding to schema
* @param {array} path - Accumulates current path (names of all properties to go through to get to the object)
* @return {array} - Array of flat records with content of all nested objects
*/
function processMany(array, schema, record = [], path = []) {
var records = [];
if (array.length == 0) {
// there is no objects in current array, just return the record
records.push(record);
} else {
array.forEach(function(obj) {
var recordClone = record.slice(0);
var r = processSingle(obj, schema, recordClone, path);
// there are objects in current array, accumulate whatever is parsed from each object and return it
records = records.concat(r);
});
}
return records;
}
/**
* @param {hash} object - The data to be converted into flat view
* @param {array} schema - Accumulates names and represents names of the columns
* @param {array} record - Array with values accumulated so far with indexes corresponding to schema
* @param {array} path - Accumulates current path (names of all properties to go through to get to the object)
* @return {array} - Array of flat records with content of all nested objects
*/
function processSingle(object, schema, record, path) {
var nestedObjects = [],
nestedArrays = [];
var records = [];
Object.keys(object).forEach(function(key) {
var value = object[key];
// we need to treat differently arrays, objects and plain values
if (Array.isArray(value)) {
// it is array, save it for later
nestedArrays.push({
key: key,
value: value
});
} else if (value && value.constructor == Object) {
// it is object (hash), save it for later
nestedObjects.push({
key: key,
value: value
});
} else {
// it is plain value, just add it to record
var keyPath = path.concat(key);
record = processSimpleValue(value, schema, record, keyPath);
}
});
if (nestedObjects.length == 0) {
// if there are no nested objects we have only one record so far
records = [record];
} else {
// if there are nested objects, each of them has one or more records in it
// if a nested object contains more than one record each next nested object
// will fill each of the records returned by the previous nested object
records = [record];
nestedObjects.forEach(function(keyValue) {
var thisObjectRecords = [];
records.forEach(function(record) {
var keyPath = path.concat(keyValue.key);
var recordClone = record.slice(0);
var object = keyValue.value;
var r = processSingle(object, schema, recordClone, keyPath)
thisObjectRecords = thisObjectRecords.concat(r);
});
records = thisObjectRecords; // one or more records here
});
}
if (nestedArrays.length == 0) {
// we have no nested arrays; it means we return everything we have processed so far
return records;
} else {
// each of the nested arrays will return one or more records, we need to accumulate it and return
var nestedRecords = [];
nestedArrays.forEach(function(keyValue) {
// we need to fill each of the records we have with information from nested arrays
records.forEach(function(record) {
var keyPath = path.concat(keyValue.key);
var recordClone = record.slice(0);
var array = keyValue.value;
var r = processMany(array, schema, recordClone, keyPath)
nestedRecords = nestedRecords.concat(r); // one or more records here
});
});
return nestedRecords;
}
}
/**
* @param {string|number|null} value - The data to be added to the record
* @param {array} schema - Accumulates names and represents names of the columns
* @param {array} record - Array with values accumulated so far with indexes corresponding to schema
* @param {array} path - Accumulates current path (names of all properties to go through to get to the object)
*/
function processSimpleValue(value, schema, record, path) {
var index = addToSchema(schema, path);
record[index] = value;
return record;
}
function pathToS(path) {
return path.join('.');
}
/**
* Returns index of of the path in schema, adds the path to the schema if it is not present in it
* @return {number} index of current path in schema
*/
function addToSchema(schema, path) {
var pathS = pathToS(path);
var i = schema.indexOf(pathS);
if (i < 0) {
i = schema.length;
schema.push(pathS);
}
return i;
}
var flatHeaders = [];
var flatData = processMany(data, flatHeaders);
答案 1 :(得分:0)
确实没有变平。您可以通过下面给出的功能实现您想要的效果。如果有多个子表,它也可以工作。例如,如果您有一个包含3个元素的子表和一个包含4个元素的子表,则总共会有3*4=12
行。
var data = [{
"Products": [{
"ID": 17987
}, {
"ID": 17988
}, {
"ID": 17989
}, {
"ID": 17990
}],
"ID": "999",
"Name": "Meat"
}];
var oneToMany = function(data) {
var props = Object.keys(data).filter(function(x) {
return data.hasOwnProperty(x);
});
var nonArrayProps = props.filter(function(x) {
return !Array.isArray(data[x]);
});
var arrayProps = props.filter(function(x) {
return Array.isArray(data[x]);
});
var baseObject = {};
for (var i = 0; i < nonArrayProps.length; i++) {
baseObject[nonArrayProps[i]] = data[nonArrayProps[i]];
}
var objects = [baseObject];
for (var i = 0; i < arrayProps.length; i++) {
var prop = arrayProps[i];
var array = data[prop];
var newObjects = [];
for (var j = 0; j < array.length || j == 0; j++) {
for (var k = 0; k < objects.length || k == 0; k++) {
var newObj = clone(objects[k]);
newObj[prop] = array[j];
newObjects.push(newObj);
}
}
objects = newObjects;
}
return objects;
}
function clone(obj) {
var clone = {};
for (property in obj) {
if (obj.hasOwnProperty(property)) clone[property] = obj[property];
}
return clone;
}
function normalizeTable(tableData) {
return Array.prototype.concat.apply([], tableData.map(oneToMany));
}
console.log(normalizeTable(data));
&#13;