title: Javascript - Group and Sort Objects
body: <p>I received a challenge and have done, but I think not a good way.
  I think there is a short way to do the same thing.</p>
  
  <p>I look for MAP, REDUCE and FILTERS, but not discover a nice way.</p>
  
  <p>The objectives was: </p>
  
  <ol>
  <li>Find Duplicate Transactions.</li>
  <li>Group similars</li>
  <li>Sort the results</li>
  </ol>
  
  <p><strong>Instructions</strong>:
  Sometimes when a customer is charged, there is a duplicate transaction created. We need to find those transactions so that they can be dealt with. Everything about the transaction should be identical, except the transaction id and the time at which it occurred, as there can be up to a minute delay.</p>
  
  <p>findDuplicateTransactions(transactions)</p>
  
  <p>Find all transactions that have the same sourceAccount, targetAccount, category, amount, and the time difference between each consecutive transaction is less than 1 minute.</p>
  
  <p><strong>Input</strong>
  You can assume that all parameters will always be present and valid. However, the incoming transactions are not guaranteed to be in any particular order.</p>
  
  <p>list of transactions (Transaction[])
  <strong>Output</strong>
  list of all the duplicate transaction groups, ordered by time ascending (Transaction[][]) The groups should be sorted in ascending order of the first transaction in the group.
  Example
  The input:</p>
  
  <pre><code>[
    {
      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'
    }
  ];
  </code></pre>
  
  <p>Output expect:</p>
  
  <pre><code>[
    [
      {
        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"
      }
    ]
  ];
  </code></pre>
  
  <p>This is my code, but I did not like it. There are some nice way to do?</p>
  
  <pre><code>function findDuplicateTransactions (transactions = []) {
      var result = [];
  
      console.info("total itens :" + transactions.length);
  
        //sort
        transactions = transactions.sort((a,b)=&gt; a.time.localeCompare(b.time))
  
        //remove itens not duplicated
        result = removeItens(transactions);
  
  
        //group
        result = groupBy(result, function(item){
            return [item.sourceAccount, item.targetAccount, item.amount, item.category];
        });
  
    console.info(result);
  
        //remove UniqueElements
        result = removeUniqueElements(result);
  
  
  
        return result;
    }
  
    function removeUniqueElements(array){
        var filtered = array.filter(function(value, index, arr){
            return value.length &gt;= 2;
        });
  
        return filtered;
    }
  
    function removeItens(array){
        var itensToBeRemoved = [];
        for (var index = 0; index &lt; array.length; index++) {
            const element1 = array[index];
            var cont = 0;
  
            console.info("============== looking for: " + element1.id);
  
            for (var index2 = 0; index2 &lt; array.length; index2++) {
                const element2 = array[index2];
  
                if(element1.id != element2.id){
  
  
                  var date1 = new Date(element1.time);
                  var date2 = new Date(element2.time);
  
                  var timeDiff = Math.abs(date2.getTime() - date1.getTime());
  
                  console.info("comparing :" + element1.id + "&lt;-&gt;" + element2.id + " diff: " + timeDiff);
  
  
                  if( timeDiff &lt; 60000) {
                      //keep it - is similar
                      console.info("find one duplicated: " + element2.id);
                      break;
                  }else{
                      cont++;
                  }
                }
            }
  
            //console.info("cont: " + cont)
  
            if(cont == array.length-1){
              //array.splice(index, 1);
              console.info("possible duplicated: " + element1.id);
              itensToBeRemoved.push(element1.id);
            }
        }
  
        var filtered = [];
  
        for(var i=0; i&lt;itensToBeRemoved.length; i++){
            console.info("remove item: " + itensToBeRemoved[i]);
            array = arrayRemove(array, itensToBeRemoved[i]);
        }
  
      return array;
    }
  
  function arrayRemove(arr, value) {
     return arr.filter(function(ele){
         console.info("watching: " + ele.id);
         console.info("index: " + value);
         return ele.id != value;
     });
  }
  
    function groupBy( array , f ){
        var lists = {};
        array.forEach( function( o ){
            var list = JSON.stringify( f(o) );
            lists[list] = lists[list] || [];
            lists[list].push( o );  
        });
        return Object.keys(lists).map( function( list ){
            return lists[list]; 
        })
    }
  </code></pre>