C.Astraea
C.Astraea

Reputation: 185

Get array difference between multiple arrays of different sizes

Been going around in circles with this for a while.

For example let's say I have different times slots stored as this

let timechunks1 = [["09:00", "10:00", "11:00"], ["09:00", "10:00", "11:00"], ["09:00", "10:00", "11:00", "12:00"]] 
let timechunks2 = [["09:00", "10:00", "11:00"], ["09:00", "10:00", "11:00"], ["09:00", "10:00"]]


 for (let i=0; i< timechunks.length; i++) {
 differences.push(_.difference(timechunks[0], timechunks[i]))      
}

Would need to extract 12:00 since it doesn't appear in others. Closest I got was with underscore _difference but alas it's not doing what I expected.

For timechunks1 I'm looking to return "12:00" For timechunks2 I'm looking for a way to return "11:00"

Added another example

[
["09:00", "10:00", "11:00" ,"13:00"],
["09:00", "10:00", "11:00", "13:00"], 
["09:00", "10:00", "11:00", "12:00"]
]  

for which it would return ["13:00", "12:00"]

Upvotes: 1

Views: 433

Answers (5)

Julian
Julian

Reputation: 4366

In set-theoretic terms, what you are looking for is the symmetric difference. You can find this set by taking the union and subtracting the intersection:

function symmetricDifference(...sets) {
    return _.difference(_.union(...sets), _.intersection(...sets));
}

Upvotes: 2

Scott Sauyet
Scott Sauyet

Reputation: 50787

You can build this on implementations of intersection, difference, and uniq. Here's how I might do it with Ramda's versions:

const notCommon = (xs, common = xs .reduce (intersection)) => 
  uniq (xs .flatMap (x => difference (x, common)))


const timechunks1 = [["09:00", "10:00", "11:00"], ["09:00", "10:00", "11:00"], ["09:00", "10:00", "11:00", "12:00"]] 
const timechunks2 = [["09:00", "10:00", "11:00"], ["09:00", "10:00", "11:00"], ["09:00", "10:00"]]
const timechunks3 = [["09:00", "10:00", "11:00" ,"13:00"], ["09:00", "10:00", "11:00", "13:00"], ["09:00", "10:00", "11:00", "12:00"]]

console .log (notCommon (timechunks1))
console .log (notCommon (timechunks2))
console .log (notCommon (timechunks3))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js"></script>
<script> const {intersection, uniq, difference} = R                  </script>

We find the elements in common to all the sets by using intersection Here we reduce over Ramda's binary version. Other versions might let you do something like common = intersection (xs) or common = intersection (...xs), depending on their exact API. Then we flatMap a difference function over the timechunks, returning the values not found in common. And finally we take only the uniq elements of that list.

Upvotes: 1

hgb123
hgb123

Reputation: 14891

You could achieve that by following these steps:

  • find the common timechunk, _.intersection(...timechunks)
  • iterate the timechunks and find the difference of each from the common, _.difference(timechunk, commons)

Below snippet could help you

const timechunks1 = [
  ["09:00", "10:00", "11:00"],
  ["09:00", "10:00", "11:00"],
  ["09:00", "10:00", "11:00", "12:00"],
]
const timechunks2 = [
  ["09:00", "10:00", "11:00"],
  ["09:00", "10:00", "11:00"],
  ["09:00", "10:00"],
]
const timechunks3 = [
  ["09:00", "10:00", "11:00", "13:00"],
  ["09:00", "10:00", "11:00", "13:00"],
  ["09:00", "10:00", "11:00", "12:00"],
]

const getDifferences = (timechunks) =>
  _.chain(timechunks)
    .map((timechunk) => _.difference(timechunk, _.intersection(...timechunks)))
    .flatten()
    .uniq()
    .value()

console.log(getDifferences(timechunks1))
console.log(getDifferences(timechunks2))
console.log(getDifferences(timechunks3))
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

Upvotes: 0

nip
nip

Reputation: 1697

function findUniqueTimeSlots(timechunks) {
  const hm = {};
  timechunks.flat(1).forEach(el => {
    if (hm.hasOwnProperty(el)) {
      hm[el] += 1;
    } else {
      hm[el] = 1;
    }
  });
  return Object.keys(hm).filter(key => hm[key] === 1);
}

Upvotes: 0

Vasanth Gopal
Vasanth Gopal

Reputation: 1285

Here is an immutable way of doing it

function findTimeSlot(timechunks){
    const slots = _.map(_.zip(...timechunks), _.compact);
    const maxChunk = _.max(_.map(slots, slot => slot.length));

    return _.unique(_.find(slots, (slot) => slot.length < maxChunk));
}

returns

["11:00"] for findTimeSlot(timechunks2)

And

["12:00"] for findTimeSlot(timechunks1)

Let know if it works.

Upvotes: 0

Related Questions