Reputation: 3714
I am looking for an elegant (and comprehensible in a year's time) solution for a collection filtering challenge. I am querying a log database and get some sort of the following data structure
| refId | isDeleted | loggedDate |
|---------|-------------|---------------------|
| 1 | 0 | 2018-02-23 21:39:05 |
| 2 | 0 | 2018-02-23 21:39:05 |
| 3 | 0 | 2018-02-23 21:39:05 |
| 4 | 0 | 2018-02-23 21:39:05 |
| 2 | 1 | 2018-02-23 21:49:05 |
| 5 | 0 | 2018-02-23 21:49:05 |
| 6 | 1 | 2018-02-23 21:49:05 |
My objective is to filter out the entries which have both, isDeleted=0
&& isDeleted=1
, and to leave only those which are either isDeleted=0
or isDeleted=1
. In this example I should end up with datasets of 1, 3, 4, 5 and 6.
Thx.
PS. The collection might hold up to 1000 entries, if you were to ask...
Upvotes: 0
Views: 1801
Reputation: 3714
Thanks to Don't Panic advice, I've come up with the following chain.
$collection->groupBy('refId')
->filter( function($refGroup) {
if ( $refGroup->count() > 1 ) {
# 0 + 1
$length = $refGroup->count();
$sum = $refGroup->reduce(function($carry, $item){
return $carry + $item->isDeleted;
});
# all sum=0 refIds are OK (no deletions)
if ( $sum == 0 ) {
return $refGroup;
} else {
# all sum=1 are good if the length=1 (deleted once)
if ( $length == $sum ) {
return $refGroup;
} else {
# sum=1 and length more than 1? manipulated and deleted => ignore
return false;
}
}
} else {
return $refGroup;
}
})
->flatten(1)
->unique('refId');
The first tests are OK. Will need to test it with different datasets, though.
Upvotes: 0
Reputation: 41810
Maybe you could group by refId
and isDeleted
and filter the groups that only have one entry.
$refIds = $collection->groupBy(['refId', 'isDeleted'])->filter(function($refGroup) {
return count($refGroup) === 1;
});
I can't currently test this to verify it works, I just tried to come up with an approximation for how I would do this in SQL based on the Laravel docs.
The result would still be grouped though, so it might not be that handy depending on how you're using it.
Upvotes: 1