嵌套.unionWith,每级唯一合并

时间:2019-01-10 16:50:45

标签: javascript recursion lodash

原始数据如下:

let AddressesBook = [
{
    "userName": "Jay12",
    "doorNumber": "1512",
    "cityID": 19,
    "city": "London",
    "countryID": 1,
    "country": "UK",
    "houseType": "private"
},
{
    "userName": "Jay12",
    "doorNumber": "2003",
    "cityID": 14,
    "city": "York",
    "countryID": 1,
    "universe": "UK",
    "houseType": "private"
},
{
    "userName": "Jay12",
    "doorNumber": "435",
    "cityID": 31,
    "city": "Washington",
    "countryID": 2,
    "universe": "USA",
    "houseType": "private"
},
{
    "userName": "Jay12",
    "doorNumber": "1123",
    "cityID": 18,
    "city": "Oxford",
    "countryID": 1,
    "universe": "UK",
    "houseType": "private"
}


];

我正在使用Lodash和相关的唯一ID映射数据层次结构  化作字典:

function nestMaker(list, order) {
if (_.isEmpty(order)) return [];
let groups = _.groupBy(list, _.first(order));
return _.map(groups, (children, key) => {
    let group = {};
    group[_.first(order)] = key;
    group.data = nestMaker(children, _.drop(order));
    return _.isEmpty(group.data) ? _.omit(group, 'data') : group;
  });
  }


let hierarchical = nestMaker(AddressesBook, [
"countryID",
"cityID",
"houseType",
"doorNumber"]
 );

它工作正常,但我想在对象的每个级别中具有与ID相关的名称。 不幸的是,您不能在两个键上使用_.groupBy。我当时正在考虑将_.unionWith与第一次迭代分开使用,但是我找不到递归地忽略不必要数据的方法。

预期输出:

 let output =
  [
    {
        "countryID": "1",
        "country": "UK",
        "data": [
            {
                "cityID": "14",
                "city": "York",
                "data": [
                    {
                        "houseType": "private",
                        "data": [
                            {
                                "doorNumber": "2003"
                            }
                        ]
                    }
                ]
            },
            {
                "cityID": "18",
                "city": "Oxford",
                "data": [
                    {
                        "houseType": "private",
                        "data": [
                            {
                                "doorNumber": "1123"
                            }
                        ]
                    }
                ]
            },
            {
                "cityID": "19",
                "city": "London",
                "data": [
                    {
                        "houseType": "private",
                        "data": [
                            {
                                "doorNumber": "1512"
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        "countryID": "2",
        "country": "USA",
        "data": [
            {
                "cityID": "31",
                "city": "Washington",
                "data": [
                    {
                        "houseType": "private",
                        "data": [
                            {
                                "doorNumber": "435"
                            }
                        ]
                    }
                ]
            }
        ]
      }
    ];

2 个答案:

答案 0 :(得分:1)

这有点手动,但是可以完成工作。

let AddressesBook = [{
    "userName": "Jay12",
    "doorNumber": "1512",
    "cityID": 19,
    "city": "London",
    "countryID": 1,
    "country": "UK",
    "houseType": "private"
  },
  {
    "userName": "Jay12",
    "doorNumber": "2003",
    "cityID": 14,
    "city": "York",
    "countryID": 1,
    "country": "UK",
    "houseType": "private"
  },
  {
    "userName": "Jay12",
    "doorNumber": "435",
    "cityID": 31,
    "city": "Washington",
    "countryID": 2,
    "country": "USA",
    "houseType": "private"
  },
  {
    "userName": "Jay12",
    "doorNumber": "1123",
    "cityID": 18,
    "city": "Oxford",
    "countryID": 1,
    "country": "UK",
    "houseType": "private"
  }


];
database = []
AddressesBook.forEach(a => {
  doesExist = database.some(d => (d.countryID == a.countryID))
  if (doesExist) {
    let instance = database.filter(d => d.countryID == a.countryID)[0]
    instance.data.push({
      "cityID": a.cityID,
      "city": a.city,
      "data": [{
        "houseType": a.houseType,
        "data": [{
          "doorNumber": a.doorNumber
        }]
      }]
    })
  } else {
    database.push({
      "countryID": a.countryID,
      "country": a.country,
      "data": [{
        "cityID": a.cityID,
        "city": a.city,
        "data": [{
          "houseType": a.houseType,
          "data": [{
            "doorNumber": a.doorNumber
          }]
        }]
      }]
    })
  }
})

console.log(database)

答案 1 :(得分:1)

您可以获得组中的第一个项目,并从该项目中提取名称(国家/地区,城市):

const AddressesBook = [{"userName":"Jay12","doorNumber":"1512","cityID":19,"city":"London","countryID":1,"country":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"2003","cityID":14,"city":"York","countryID":1,"country":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"435","cityID":31,"city":"Washington","countryID":2,"country":"USA","houseType":"private"},{"userName":"Jay12","doorNumber":"1123","cityID":18,"city":"Oxford","countryID":1,"country":"UK","houseType":"private"}];

const nestMaker = (list, order) => {
  if (_.isEmpty(order)) return [];
  
  const idKey = _.first(order);
  const nameKey = idKey.replace('ID', '');
  let groups = _.groupBy(list, idKey);
  
  return _.map(groups, (children, key) => {
    const group = {};
    const child = _.first(children);
    
    group[idKey] = key;
    if(_.has(child, nameKey)) group[nameKey] = child[nameKey];
    
    group.data = nestMaker(children, _.drop(order));
    return _.isEmpty(group.data) ? _.omit(group, 'data') : group;
  });
}


const hierarchical = nestMaker(AddressesBook, [
  "countryID",
  "cityID",
  "houseType",
  "doorNumber"
]);

console.log(hierarchical);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

如果id和name键不是遵循相同的模式,则可以按以下顺序将它们明确表示为条目:

const AddressesBook = [{"userName":"Jay12","doorNumber":"1512","cityID":19,"city":"London","countryID":1,"universe":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"2003","cityID":14,"city":"York","countryID":1,"universe":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"435","cityID":31,"city":"Washington","countryID":2,"universe":"USA","houseType":"private"},{"userName":"Jay12","doorNumber":"1123","cityID":18,"city":"Oxford","countryID":1,"universe":"UK","houseType":"private"}];

const nestMaker = (list, order) => {
  if (_.isEmpty(order)) return [];
  
  const entry = _.first(order);
  const [idKey, nameKey] = Array.isArray(entry) ? entry : [entry];
  let groups = _.groupBy(list, idKey);
  
  return _.map(groups, (children, key) => {
    const group = {}; 
    const child = _.first(children);
    
    group[idKey] = key;
    if(_.has(child, nameKey)) group[nameKey] = child[nameKey];
    
    group.data = nestMaker(children, _.drop(order));
    return _.isEmpty(group.data) ? _.omit(group, 'data') : group;
  });
}


const hierarchical = nestMaker(AddressesBook, [
  ["countryID", "universe"],
  ["cityID", "city"],
  "houseType",
  "doorNumber"
]);

console.log(hierarchical);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>