对对象数组进行排序并采用N个元素

时间:2018-11-06 15:41:57

标签: javascript arrays node.js sorting lodash

在NodeJS服务中,我有一个数组,其中包含具有以下属性的对象:

  • 批处理类型:字符串
  • batchId:字符串(是哈希)
  • transactionId:字符串(是哈希)

此数组存储所有不同类型批次的交易。

基本上,我需要从数组中获取N个项目,但要遵守某些规则:

  1. 每种类型的批次至少获得1件物品
  2. 每个batchId至少获得1个物品
  3. 有时阵列只能具有一种批处理类型

这是数组的示例:

let batchTransactionsArray = [
  { batchType: 'type1', batchId: '123', transactionId: 'ffasf23' },
  { batchType: 'type1', batchId: '312', transactionId: '423' },
  { batchType: 'type1', batchId: '123', transactionId: '534' },
  { batchType: 'type1', batchId: '312', transactionId: '86' },
  { batchType: 'type2', batchId: '111', transactionId: '97' },
  { batchType: 'type1', batchId: '312', transactionId: '1945' },
  { batchType: 'type1', batchId: '123', transactionId: '79' },
  { batchType: 'type1', batchId: '312', transactionId: '79' },
  { batchType: 'type3', batchId: '425', transactionId: '1555645' },
  { batchType: 'type1', batchId: '123', transactionId: 'fg5' },
  { batchType: 'type1', batchId: '123', transactionId: 'jkh5' },
  { batchType: 'type1', batchId: '312', transactionId: '53j' },
  { batchType: 'type1', batchId: '111', transactionId: '4545' },
  { batchType: 'type2', batchId: '111', transactionId: '534l' },
  { batchType: 'type1', batchId: '111', transactionId: 'jkg435' },
  { batchType: 'type1', batchId: '111', transactionId: 'gfxg23' },
  { batchType: 'type1', batchId: '111', transactionId: '7asdt' },
  { batchType: 'type1', batchId: '222', transactionId: 'jdsa7' },
  { batchType: 'type3', batchId: '663', transactionId: '12423445' },
  { batchType: 'type1', batchId: '111', transactionId: '89saf6' },
  { batchType: 'type1', batchId: '111', transactionId: '12h3g' },
  { batchType: 'type1', batchId: '111', transactionId: '4h3k2hj' },
  { batchType: 'type3', batchId: '663', transactionId: '145' }
];

我需要的输出示例是(如果我要从数组中进行5个事务):

[{ batchType: 'type1', batchId: '123', transactionId: '534' },
 { batchType: 'type1', batchId: '312', transactionId: '86' },
 { batchType: 'type2', batchId: '111', transactionId: '97' },
 { batchType: 'type2', batchId: '111', transactionId: '534l' },
 { batchType: 'type3', batchId: '663', transactionId: '145' }
]

对transactionIds进行排序的标准是随机的,没有特定的顺序可以满足。

我正在尝试一些lodash函数,例如groupBy和sortBy,但是还没有运气。

这是我正在玩的一个jsfiddle:https://jsfiddle.net/20jh3ze7/

我非常感谢您的建议。

3 个答案:

答案 0 :(得分:1)

您可以使用lodash做类似的事情:

let data = [ { batchType: 'type1', batchId: '123', transactionId: 'ffasf23' }, { batchType: 'type1', batchId: '312', transactionId: '423' }, { batchType: 'type1', batchId: '123', transactionId: '534' }, { batchType: 'type1', batchId: '312', transactionId: '86' }, { batchType: 'type2', batchId: '111', transactionId: '97' }, { batchType: 'type1', batchId: '312', transactionId: '1945' }, { batchType: 'type1', batchId: '123', transactionId: '79' }, { batchType: 'type1', batchId: '312', transactionId: '79' }, { batchType: 'type3', batchId: '425', transactionId: '1555645' }, { batchType: 'type1', batchId: '123', transactionId: 'fg5' }, { batchType: 'type1', batchId: '123', transactionId: 'jkh5' }, { batchType: 'type1', batchId: '312', transactionId: '53j' }, { batchType: 'type1', batchId: '111', transactionId: '4545' }, { batchType: 'type2', batchId: '111', transactionId: '534l' }, { batchType: 'type1', batchId: '111', transactionId: 'jkg435' }, { batchType: 'type1', batchId: '111', transactionId: 'gfxg23' }, { batchType: 'type1', batchId: '111', transactionId: '7asdt' }, { batchType: 'type1', batchId: '222', transactionId: 'jdsa7' }, { batchType: 'type3', batchId: '663', transactionId: '12423445' }, { batchType: 'type1', batchId: '111', transactionId: '89saf6' }, { batchType: 'type1', batchId: '111', transactionId: '12h3g' }, { batchType: 'type1', batchId: '111', transactionId: '4h3k2hj' }, { batchType: 'type3', batchId: '663', transactionId: '145' } ];

const customTake = (d, n) => {
  const roundRobinUnion = (arr) => {
    let res = []
    while (_.flatten(arr).length)
      _.each(arr, x => x.length ? res.push(_.remove(x, (y, i) => i == 0)) : null)
    return _.flatten(res)
  }
  const groups = _(d)
    .orderBy(['batchType', 'batchId'])
    .groupBy('batchType')
    .mapValues(x => _.values(_.groupBy(x, 'batchId')))
    .map(x => roundRobinUnion(x))
    .value()
  return _.take(roundRobinUnion(groups), n)
}

console.log(customTake(data, 3))
console.log(customTake(data, 5))
console.log(customTake(data, 6))
console.log(customTake(data, 8))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

这个想法是将batchTypebatchId归为一组,并将此问题视为循环联盟。您将遍历每个数组索引,并对每个元素进行并集。

如果您关心排序的最后顺序,您总是可以在结尾处再做一个orderBy,等等。

这是roundRobinUnion想法的简单示例:

const data = [
  [1, 2, 3],
  [1],
  [5, 6]
]

const roundRobinUnion = (arr) => {
  let res = []
  while (_.flatten(arr).length)
    _.each(arr, x => x.length ? res.push(_.remove(x, (y, i) => i == 0)) : null)
  return _.flatten(res)
}

console.log(roundRobinUnion(data))  // [1,1,5,2,6,3]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

答案 1 :(得分:0)

您可以按以下步骤进行操作:

  • 首先添加唯一的batchType元素(这符合第一个条件)
  • 然后添加唯一的batchId元素(符合第二个条件)
  • 如果仍有剩余空间(最多N个元素),请用剩余的元素填充数组

要检查唯一性,可以使用Set。由于您说的是使用lodash,因此可以使用_.groupBy将数组按batchItembatchId进行分组,以从每个组中获取唯一元素。

let batchTransactionsArray = [
  { batchType: 'type1', batchId: '123', transactionId: 'ffasf23' },
  { batchType: 'type1', batchId: '312', transactionId: '423' },
  { batchType: 'type1', batchId: '123', transactionId: '534' },
  { batchType: 'type1', batchId: '312', transactionId: '86' },
  { batchType: 'type2', batchId: '111', transactionId: '97' },
  { batchType: 'type1', batchId: '312', transactionId: '1945' },
  { batchType: 'type1', batchId: '123', transactionId: '79' },
  { batchType: 'type1', batchId: '312', transactionId: '79' },
  { batchType: 'type3', batchId: '425', transactionId: '1555645' },
  { batchType: 'type1', batchId: '123', transactionId: 'fg5' },
  { batchType: 'type1', batchId: '123', transactionId: 'jkh5' },
  { batchType: 'type1', batchId: '312', transactionId: '53j' },
  { batchType: 'type1', batchId: '111', transactionId: '4545' },
  { batchType: 'type2', batchId: '111', transactionId: '534l' },
  { batchType: 'type1', batchId: '111', transactionId: 'jkg435' },
  { batchType: 'type1', batchId: '111', transactionId: 'gfxg23' },
  { batchType: 'type1', batchId: '111', transactionId: '7asdt' },
  { batchType: 'type1', batchId: '222', transactionId: 'jdsa7' },
  { batchType: 'type3', batchId: '663', transactionId: '12423445' },
  { batchType: 'type1', batchId: '111', transactionId: '89saf6' },
  { batchType: 'type1', batchId: '111', transactionId: '12h3g' },
  { batchType: 'type1', batchId: '111', transactionId: '4h3k2hj' },
  { batchType: 'type3', batchId: '663', transactionId: '145' }
];

function getNItems(array, N = 5) {
  if (N >= array.length) return array;
  let batchTypeGroups = _.groupBy(array, e => e.batchType),
      res  = new Set(), batchIds = new Set();
  
  // add unique batchTypes
  for (let [batchType, elements] of Object.entries(batchTypeGroups)) {
    if (res.size === N) break;
    let d = elements.find(e => !batchIds.has(e.batchId));
    if (d) {
      res.add(d);
      batchIds.add(d.batchId);
    } else {
      res.add(elements[0]);
    }
  }
  
  // add remaining unique batchIds
  let batchIdGroups = _.groupBy(array.filter(e => !batchIds.has(e.batchId)), e => e.batchId);
  for (let [batchId, elements] of Object.entries(batchIdGroups)) {
    if (res.size === N) break;
    res.add(elements[0]);
  }
  
  // add any remaining elements until we have N elements
  for (let e of array) {
    if (res.size === N) break;
    res.add(e);
  }
  
  return Array.from(res);
}

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

答案 2 :(得分:0)

我认为对于这种类型的问题,我们不需要额外的依赖关系。

我们可以使用普通的javascript:)

let batchTransactionsArray = [
  { batchType: "type1", batchId: "123", transactionId: "ffasf23" },
  { batchType: "type1", batchId: "312", transactionId: "423" },
  { batchType: "type1", batchId: "123", transactionId: "534" },
  { batchType: "type1", batchId: "312", transactionId: "86" },
  { batchType: "type2", batchId: "111", transactionId: "97" },
  { batchType: "type1", batchId: "312", transactionId: "1945" },
  { batchType: "type1", batchId: "123", transactionId: "79" },
  { batchType: "type1", batchId: "312", transactionId: "79" },
  { batchType: "type3", batchId: "425", transactionId: "1555645" },
  { batchType: "type1", batchId: "123", transactionId: "fg5" },
  { batchType: "type1", batchId: "123", transactionId: "jkh5" },
  { batchType: "type1", batchId: "312", transactionId: "53j" },
  { batchType: "type1", batchId: "111", transactionId: "4545" },
  { batchType: "type2", batchId: "111", transactionId: "534l" },
  { batchType: "type1", batchId: "111", transactionId: "jkg435" },
  { batchType: "type1", batchId: "111", transactionId: "gfxg23" },
  { batchType: "type1", batchId: "111", transactionId: "7asdt" },
  { batchType: "type1", batchId: "222", transactionId: "jdsa7" },
  { batchType: "type3", batchId: "663", transactionId: "12423445" },
  { batchType: "type1", batchId: "111", transactionId: "89saf6" },
  { batchType: "type1", batchId: "111", transactionId: "12h3g" },
  { batchType: "type1", batchId: "111", transactionId: "4h3k2hj" },
  { batchType: "type3", batchId: "663", transactionId: "145" }
];

const getUniqueBatches = () => {
  const uniqueBatches = [];

  batchTransactionsArray.forEach(b => {
    const batchByType = uniqueBatches.find(findBatchByType(b.batchType));
    const batchById = uniqueBatches.find(findBatchByBatchId(b.batchId));
    if (!batchByType || !batchById) {
      uniqueBatches.push(b);
    }
  });

  return uniqueBatches;
};

const findBatchByType = batchType => {
  return batch => {
    return batch.batchType === batchType;
  };
};
const findBatchByBatchId = batchId => {
  return batch => {
    return batch.batchId === batchId;
  };
};

console.log(getUniqueBatches());

相关问题