0

I have an object array. Every gateType:entry needs to be followed by gateType:exit object.

The problem is some entry object and some exit objects are missing/skipped. I need to create an object array that has the missing objects.

            [{
                "dateTime": "2016-01-28 15:18:26",
                "gateType": "entry",
            }, {
                "dateTime": "2016-01-28 15:18:27",
                "gateType": "exit",
            }, {
                "dateTime": "2016-01-28 15:19:26",
                "gateType": "entry",
            }, {
                "dateTime": "2016-01-28 15:19:27",
                "gateType": "exit",
            }, {
                "dateTime": "2016-01-28 15:20:26",
                "gateType": "entry",
            },
// here is the exit object is missing for above
            {
                "dateTime": "2016-01-28 15:21:25",
                "gateType": "entry",
            }, {
                "dateTime": "2016-01-28 15:21:26",
                "gateType": "exit",
            }, {
                "dateTime": "2016-01-28 15:22:25",
                "gateType": "entry", 
            }, {
                "dateTime": "2016-01-28 15:22:26",
                "gateType": "exit",
            }, 
// here is the entry object is missing for below
            {
                "dateTime": "2016-01-28 15:23:26",
                "gateType": "exit",
            }]

Each entry needs to be followed by exit. But as you can see some entry or exit objects does not exist.

The solution for above example is:

            [{
                "dateTime": "2016-01-28 15:20:26",
                "gateType": "exit",
            },{
                "dateTime": "2016-01-28 15:23:26",
                "gateType": "enty",
            }]

My solution was this but it doesn't work like i expected :

function detectMissingOnes(rows) {

        var missings = [];
        var current = null;

        rows.forEach(function (key, index) {


            if (index == 0) {

                if(key.gateType == "exit"){


                    var resultDate = moment(key.dateTime);
                    resultDate = resultDate.subtract(1, 'seconds').format("YYYY-MM-DD HH:mm:ss");

                    missings.push({
                        dateTime: resultDate,
                        gateNumber: key.gateNumber,
                        gateType: "entry",
                        personId: key.personId,
                        fix: 1
                    });

                }

                current = key;
                return true;
            }

            if (current.gateType == key.gateType) {

                var type = key.gateType == "entry" ? "exit" : "entry";

                var resultDate = moment(current.dateTime);
                if(type == "entry"){
                    resultDate = resultDate.subtract(1, 'seconds').format("YYYY-MM-DD HH:mm:ss");
                }else {
                    resultDate = resultDate.add(1, 'seconds').format("YYYY-MM-DD HH:mm:ss");
                }


                missings.push({
                    dateTime: resultDate,
                    gateNumber: current.gateNumber,
                    gateType: type,
                    personId: current.personId,
                    fix: 1
                });

            }

            current = key;

        });

        return missings;
    }

Could you help me to write the algorithm with or without lodash?

2 Answers 2

1

Below is code that returns the missing records. In your question you did not mention to add/subtract a second in missing records, but in your code this was present, so I did the same.

I did not make use of any library, so even the manipulation with seconds is done via standard JavaScript functions, which make it a bit longer.

This live snippet allows you to enter the input array (JSON), and get the result of the function (also JSON).

// main algorithm:
function detectMissingOnes(rows) {
    var collect = rows.reduce(function (collect, curr) {
        var expectedMove = collect.openEntry ? "exit" : "entry";
        var expectedPerson = collect.openEntry ? collect.openEntry.personId : curr.personId;
        console.log('expected move: ', expectedMove, ' person: ', expectedPerson);
        console.log('current move: ', curr.gateType, ' person:', curr.personId);
        if (expectedMove == curr.gateType && 
                expectedPerson == curr.personId) {
            console.log('ok');
            // OK, we have the expected gate type and personID.
            // If this is an entry, keep track of it, otherwise clear tracks
            collect.openEntry = collect.openEntry ? null : curr; // toggle
        } else {
            console.log('mismatch');
            // not OK, add to orphans list
            if (collect.openEntry)       collect.orphans.push(collect.openEntry);
            if (curr.gateType == 'exit') collect.orphans.push(curr);
            // If this is an entry, replace previous track
            collect.openEntry = curr.gateType == 'entry' ? curr : null;
        }
        return collect;
    }, {orphans: [], openEntry: null}); // initial value of collect
    
    // if last one was an "entry", add it to the orphans list
    if (collect.openEntry) {
        collect.orphans.push(collect.openEntry);
    }
    
    // for all orphans: return the missing counter part.
    return collect.orphans.map(function(orphan) {
        var mydate = new Date(orphan.dateTime.replace(/^(.{10}) (.{8})$/, '$1T$2Z'))
        // add/subtract one second:
        mydate = new Date(+mydate + 1000*(orphan.gateType == "entry" ? 1 : -1));
        return {
            id:         orphan.id,
            dateTime:   mydate.toISOString().replace(/^(.{10})T(.{8}).*$/, '$1 $2'),
            gateNumber: orphan.gateNumber,
            gateType:   orphan.gateType == "entry" ? "exit" : "entry",
            personId:   orphan.personId,
            fix:        orphan.fix
        };
    });
}

// default input data:
var data = [
  {
    "id": 517,
    "dateTime": "2016-01-29 13:17:46",
    "gateNumber": "192.168.1.206",
    "gateType": "exit",
    "personId": 1,
    "fix": 0
  },
  {
    "id": 568,
    "dateTime": "2016-01-29 14:03:44",
    "gateNumber": "192.168.1.203",
    "gateType": "entry",
    "personId": 1,
    "fix": 0
  },
  {
    "id": 675,
    "dateTime": "2016-01-29 14:10:07",
    "gateNumber": "192.168.1.203",
    "gateType": "entry",
    "personId": 1,
    "fix": 0
  },
  {
    "id": 108,
    "dateTime": "2016-01-29 14:11:51",
    "gateNumber": "192.168.1.205",
    "gateType": "entry",
    "personId": 1,
    "fix": 0
  },
  {
    "id": 170,
    "dateTime": "2016-01-28 14:27:58",
    "gateNumber": "192.168.1.206",
    "gateType": "exit",
    "personId": 2,
    "fix": 0
  },
  {
    "id": 66,
    "dateTime": "2016-01-28 14:33:07",
    "gateNumber": "192.168.1.200",
    "gateType": "exit",
    "personId": 2,
    "fix": 0
  },
  {
    "id": 395,
    "dateTime": "2016-01-28 16:26:04",
    "gateNumber": "192.168.1.206",
    "gateType": "exit",
    "personId": 2,
    "fix": 0
  }
];
// Get input controls:
var input = document.getElementById('input');
var output = document.getElementById('output');
var button = document.getElementById('button');

// default input value:
input.value = JSON.stringify(data, null, 2);

// execute process on button click:
button.onclick = function () {
    var data = JSON.parse(input.value);
    var missing = detectMissingOnes(data);
    output.textContent = JSON.stringify(missing, null, 2);
}
div { bottom: 0; right: 0; left: 0; top: 0; position: absolute }
table { with: 100%; height: 100% }
tr.page { with: 100%; height: 100% }
td { vertical-align: top; width: 50%}
textarea { min-width: 320px; width: 100%; height:100% }
<div class="big"><table border=1>
    <tr><th>Enter input (JSON):<button id="button">Process</button></th>
        <th>Output</th></tr>
    <tr class="page"><td><textarea id="input"></textarea></td>
        <td><pre id="output"></pre></td></tr>
</table></div>

The function does not alter the passed argument (array). The returned array only lists the missing objects. Note that you need to adapt the code if you have other properties in your objects.

Sign up to request clarification or add additional context in comments.

4 Comments

I need to make small change but not sure how to do it. I need to take into consideration of "personId" property. I need to check if the objects has both same personIds. Could you help me with that too? thanks a lot.
Could you test with this data pastebin.com/ECry1T0f ? It seems it always miss two objects. If the function runs second time it fixes these two items too.
First time it fixed 5 item then 2 item.
Code updated. Didn't test the additional personId condition well enough. Hope it is OK now. I also added the other object properties I saw in pastebin.
1

try this:

'use strict';

let arr = [{
  "dateTime": "2016-01-28 15:18:26",
  "gateType": "entry",
}, {
  "dateTime": "2016-01-28 15:18:27",
  "gateType": "exit",
}, {
  "dateTime": "2016-01-28 15:19:26",
  "gateType": "entry",
}, {
  "id": 7244,
  "dateTime": "2016-01-28 15:19:27",
  "gateType": "exit",
}, {
  "dateTime": "2016-01-28 15:20:26",
  "gateType": "entry",
},
 // here is the exit object is missing for above
 {
   "dateTime": "2016-01-28 15:21:25",
   "gateType": "entry",
 }, {
   "dateTime": "2016-01-28 15:21:26",
   "gateType": "exit",
 }, {
   "dateTime": "2016-01-28 15:22:25",
   "gateType": "entry", 
 }, {
   "dateTime": "2016-01-28 15:22:26",
   "gateType": "exit",
 }, 
 // here is the entry object is missing for below
 {
   "dateTime": "2016-01-28 15:23:26",
   "gateType": "exit",
 }];

 function repairArr( arr )
 {
  for(let index=0; index<arr.length; index++)
  {
    let item = arr[index];

    if( index!=0 && item.gateType == arr[index-1].gateType )
    {
      arr.splice(index, 0, {
        dateTime: item.dateTime,
        gateType: item.gateType == 'entry' ? 'exit' : 'entry'
      });
    }
  };
 }

 repairArr( arr );

 console.log( arr );

4 Comments

it doesn't not work properly if the data is like ['entry','entry','entry','exit','exit'] -> needs to return ['entry','exit','entry','exit','entry','exit','entry','exit','entry','exit'] but returns something else.
@serdem420, why you say it should then return ['entry','exit','entry','exit','entry','exit','entry','exit','entry','exit'] . In your question you say it should return only the missing records, not the completed array. So I would expect output to be: ['exit','exit','exit','entry','entry']. Please clarify?
@trincot, you are right, i was after the missing ones not the whole array. reason i explained that way because the answer took that approach.
@Alexey, Thank you very much for your answer. I have used this approach with few fixes(such as if the first object is exit it messes up, i didn't want the whole array, just the missing one like above comment pointed out etc.) Anyway thanks a lot!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.