Поиск дубликатов в массиве объектов транзакций с использованием JavaScript и комбинированных дубликатов в массиве объектов массива - PullRequest
0 голосов
/ 26 ноября 2018

У меня есть массив объектов транзакций, где мне нужно найти дубликаты, основанные на свойстве (объект является дубликатом, если все его значения одинаковы, кроме ID и TIME, разница во времени должна быть в пределах 1 минуты).Мне нужно объединить идентичные дубликаты транзакций как объекты Array.

Ниже приведен ввод транзакций.

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

var newArray = transactions.reduce(function(acc, curr) {
      //finding Index in the array where the NamaCategory matched
      var findIfduplicateExist = acc.findIndex(function(item) {
        let accepoch = new Date(item.time).valueOf();
        let currepoch= new Date(curr.time).valueof();
        if(item.sourceAccount === curr.sourceAccount &&
        item.targetAccount===curr.targetAccount &&
        item.amount===curr.amount&&
        accepoch<currepoch+(1*60*1000))
          let obj={
           'id':curr.id,
            'sourceAccount':curr.sourceAccount,
            'targetAccount':curr.targetAccount,
            'time':curr.time,
            'category':curr.category,
            'amount':curr.amount 
          }
      })
      // if in the new array no such object exist, create a new object 
      if (findIfNameExist === -1) {
        acc.push(obj)
      } else {
        // if attributes matches , then push the value 
        acc[findIfNameExist].value.push(curr)
      }
  return acc;

}, []);

Входные транзакции:

[
  {
    id: 3,
    sourceAccount: 'A',
    targetAccount: 'B',
    amount: 100,
    category: 'eating_out',
    time: '2018-03-02T10:34:30.000Z'
  },
  {
    id: 1,
    sourceAccount: 'A',
    targetAccount: 'B',
    amount: 100,
    category: 'eating_out',
    time: '2018-03-02T10:33:00.000Z'
  },
  {
    id: 6,
    sourceAccount: 'A',
    targetAccount: 'C',
    amount: 250,
    category: 'other',
    time: '2018-03-02T10:33:05.000Z'
  },
  {
    id: 4,
    sourceAccount: 'A',
    targetAccount: 'B',
    amount: 100,
    category: 'eating_out',
    time: '2018-03-02T10:36:00.000Z'
  },
  {
    id: 2,
    sourceAccount: 'A',
    targetAccount: 'B',
    amount: 100,
    category: 'eating_out',
    time: '2018-03-02T10:33:50.000Z'
  },
  {
    id: 5,
    sourceAccount: 'A',
    targetAccount: 'C',
    amount: 250,
    category: 'other',
    time: '2018-03-02T10:33:00.000Z'
  }
];

Ожидаемый результат следующий:

[   
  [
    {
      id: 1,
      sourceAccount: "A",
      targetAccount: "B",
      amount: 100,
      category: "eating_out",
      time: "2018-03-02T10:33:00.000Z"
    },
    {
      id: 2,
      sourceAccount: "A",
      targetAccount: "B",
      amount: 100,
      category: "eating_out",
      time: "2018-03-02T10:33:50.000Z"
    },
    {
      id: 3,
      sourceAccount: "A",
      targetAccount: "B",
      amount: 100,
      category: "eating_out",
      time: "2018-03-02T10:34:30.000Z"
    }  
  ], 
  [
    {
      id: 5,
      sourceAccount: "A",
      targetAccount: "C",
      amount: 250,
      category: "other",
      time: "2018-03-02T10:33:00.000Z"
    },
    {
      id: 6,
      sourceAccount: "A",
      targetAccount: "C",
      amount: 250,
      category: "other",
      time: "2018-03-02T10:33:05.000Z"
    }   
  ] 
]

Ответы [ 3 ]

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

Вы также можете использовать Array.sort и Array.forEach, как показано ниже, для достижения этого

Я изначально отсортировал массив путем объединения значений свойств (исключая id и time) и увеличения метки времени

let arr = [{  id: 3,  sourceAccount: 'A',  targetAccount: 'B',  amount: 100,  category: 'eating_out',  time: '2018-03-02T10:34:30.000Z'},{  id: 1,  sourceAccount: 'A',  targetAccount: 'B',  amount: 100,  category: 'eating_out',  time: '2018-03-02T10:33:00.000Z'},{  id: 6,  sourceAccount: 'A',  targetAccount: 'C',  amount: 250,  category: 'other',  time: '2018-03-02T10:33:05.000Z'},{  id: 4,  sourceAccount: 'A',  targetAccount: 'B',  amount: 100,  category: 'eating_out',  time: '2018-03-02T10:36:00.000Z'},{  id: 2,  sourceAccount: 'A',  targetAccount: 'B',  amount: 100,  category: 'eating_out',  time: '2018-03-02T10:33:50.000Z'},{  id: 5,  sourceAccount: 'A',  targetAccount: 'C',  amount: 250,  category: 'other',  time: '2018-03-02T10:33:00.000Z'}];

let res = []
 ,  getKey = ({id, time, ...rest}) => Object.entries(rest).map(([k, v]) => k + '-' + v).join(';')
 ,  getTimeDiff = (t1, t2) => Math.abs(new Date(t1).getTime() - new Date(t2).getTime())

arr.sort((a,b) => {
    let akey = getKey(a)
      , bkey = getKey(b)
  
    return akey.localeCompare(bkey) || +new Date(a.time) - +new Date(b.time)
  })
  .forEach((d, i, t) => 
    i == 0 || 
      (getKey(d) == getKey(t[i-1]) && getTimeDiff(t[i-1].time, d.time)/1000 < 60)
      ? res.push((res.pop() || []).concat(d))
      : res.push([d])
  )

console.log(res)
0 голосов
/ 26 ноября 2018

Это может быть сделано кратко через один Array.sort , Array.reduce и Object.values ​​:

const data = [{ id: 3, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:34:30.000Z' }, { id: 1, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:33:00.000Z' }, { id: 6, sourceAccount: 'A', targetAccount: 'C', amount: 250, category: 'other', time: '2018-03-02T10:33:05.000Z' }, { id: 4, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:36:00.000Z' }, { id: 2, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:33:50.000Z' }, { id: 5, sourceAccount: 'A', targetAccount: 'C', amount: 250, category: 'other', time: '2018-03-02T10:33:00.000Z' }] 

const sort = arr => arr.sort((a,b) =>`${a.id}${a.time}`.localeCompare(`${b.id}${b.time}`))
const getTime = obj => new Date(obj.time).getTime()
const isDub = (arr, obj) => arr.length ? Math.abs(getTime(arr[arr.length-1]) - getTime(obj))/1000 > 60 : false

const result = Object.values(sort(data).reduce((r, c) => {
  let key = [c.sourceAccount, c.targetAccount].join('-')
  r[key] = isDub(r[key] || [], c) ? r[key] : [...r[key] || [], c]
  return r
}, {}))

console.log(result)

Вам необходимо предварительно отсортировать массив, чтобы иметь дело только с последней записью при сравнении дубликатов на основе ваших требований в течение минуты.

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

Будет проще (и эффективнее), когда вы впервые получите копию транзакций, отсортированных по идентификатору.Я предполагаю, что идентификатор является инкрементным числом, так что более поздние транзакции всегда будут иметь большее число.Таким образом, вам нужно только сравнить временную метку с последней в аккумуляторе:

// Example data
const transactions = [ { id: 3, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:34:30.000Z' }, { id: 1, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:33:00.000Z' }, { id: 6, sourceAccount: 'A', targetAccount: 'C', amount: 250, category: 'other', time: '2018-03-02T10:33:05.000Z' }, { id: 4, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:36:00.000Z' }, { id: 2, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:33:50.000Z' }, { id: 5, sourceAccount: 'A', targetAccount: 'C', amount: 250, category: 'other', time: '2018-03-02T10:33:00.000Z' } ];

const newArray = [...transactions].sort((a,b) => a.id - b.id).reduce( (acc, curr) => {
    let group = acc[acc.length-1], 
        prev = group && group[group.length-1];
    if (!prev || prev.sourceAccount !== curr.sourceAccount ||
                 prev.targetAccount !== curr.targetAccount ||
                 prev.amount !== curr.amount ||
                 Date.parse(prev.time) + (1*60*1000) < Date.parse(curr.time)) {
        // different keys or larger time difference: create new group
        acc.push(group = []);
    }
    group.push(curr);
    return acc;
}, []);

console.log(newArray);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...