1

Background

Let's say I have two arrays of objects. Each object in each array should be unique, but sometimes we have the same object in both arrays!

Array 1: [{fruit: "banana"}, {fruit: "orange"}]
Array 2: [{fruit: "apple"}, {fruit: "banana"}, {fruit: "strawberry"}]

Each array has a random number of objects, as you can see.

Objective

Imagine I have a function called isSameObj(obj1, obj2) that returns true or false depending if ob1 === ob2 or not.

Using this function, I want to know if Array1 has an object repeated in Array2 and vice-versa.

To achieve this, I first started with the traditional for loop.

//assuming Array1.length > Array2.length
for(const obj1 of Array1){
    for(const obj2 of Array2){
        if(isSameObj(obj1, obj2)){
            //do some work
            break;
        }
    }
}

This is the imperative way most of us are used to.

Problem

However, recently I tried functional programming. And I find it incredibly hard to implement this small example functionally!

The closest I got to success was using map, but map always traverses the entire array no matter what and I want to stop and break the loop once I find a repeated object.

Some gentlemen suggest to just throw inside the map, but that really is a solution I would rather avoid. I want to break a loop, not signal an error.

Question

How would I implement this code snippet functionally?

Cerbrus
  • 70,800
  • 18
  • 132
  • 147
Flame_Phoenix
  • 16,489
  • 37
  • 131
  • 266
  • So, what exactly is _"this code"_ supposed to do now? Return `true/false` depending on if there's an item that exists in both arrays? – Cerbrus Oct 16 '17 at 12:26
  • The object here is to have a function that given two arrays, can detect if they share an object and return that object. Otherwise, return undefined :D – Flame_Phoenix Oct 16 '17 at 12:29
  • Just use (tail) recursion. Btw, _Otherwise, return undefined_ - this isn't a good idea. In FP functions always return something, no matter how many cases they deal with. –  Oct 16 '17 at 12:34
  • 1
    @Cerbrus Jesus, have you even read my question? You just marked it as a duplicate when it is STATED that type of solution IS NOT WHAT I AM LOOKING FOR. I guess I should have put it in bold.... – Flame_Phoenix Oct 16 '17 at 12:35
  • @ftor I guess that's an idea worth exploring ! – Flame_Phoenix Oct 16 '17 at 12:36
  • @Flame_Phoenix: Please calm down. Look at the 2nd answer there. The accepted answer isn't great, but the other answer _does_ meet your requirements. The `filter` / `some` combination is as short / fast as it'll get without manual `for` loops you'd break out of. – Cerbrus Oct 16 '17 at 12:36
  • @Cerbrus It does not meet the requirements because the answer uses filter, which traverses the entire array, even after a duplicate is found. This is exactly what I am trying to avoid :D – Flame_Phoenix Oct 16 '17 at 12:44
  • @Flame_Phoenix I posted a new answer [there](https://stackoverflow.com/a/46770626/3211932), it satisfies your initial goal. Just do a combination of two finds: `const checkFirst = (a1, a2) => !!a2.find(i1 => a1.find(i2 => i2.fruit === i1.fruit));` – dhilt Oct 16 '17 at 12:45
  • Okay, there are no "iterate over array" functions that both short-circuits (`some/any`), __and__ return array entries (`map/filter`). If you want to short-circuit at the _first_ match, your best bet is a loop with a `some` in it. – Cerbrus Oct 16 '17 at 12:46
  • @dhilt: Note that [`find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find#Browser_compatibility) isn't supported by IE – Cerbrus Oct 16 '17 at 12:47
  • @Cerbrus So, let's use `some`... – dhilt Oct 16 '17 at 12:49
  • @dhilt: `some` doesn't return array entries. That outer `find` would have to be replaced with a `for` loop. – Cerbrus Oct 16 '17 at 12:50
  • @Cerbrus But here it would be enough, I guess. The author wants true/false at the end. – dhilt Oct 16 '17 at 12:51
  • So: `const checkFirst = (a1, a2) => a2.some(i1 => a1.some(i2 => i2.fruit === i1.fruit));` – dhilt Oct 16 '17 at 12:52
  • _"detect if they share an object **and return that object.**"_ (First comment by OP here) – Cerbrus Oct 16 '17 at 12:52
  • Damn... `const findFirst = (a1, a2) => { let result; a2.some(i1 => a1.some(i2 => i2.fruit === i1.fruit ? result = i1 : false )); return result; }` – dhilt Oct 16 '17 at 12:56
  • That would work, but then I'd be wondering why someone is (ab)using `some` instead of a `for` loop you can simply `return` out of... – Cerbrus Oct 16 '17 at 13:00
  • @Cerbrus I agree with you! – dhilt Oct 16 '17 at 13:00
  • Returning true/false is not he idea here, the idea, as stated before, would be to have it return the object, or undefined if nothing. I will have a look at your new answer, although I have to wonder why you posted it there instead of here, since in the other question no one is asking for a short-circuit. – Flame_Phoenix Oct 16 '17 at 13:02
  • @Flame_Phoenix This question is closed for answers, unfortunately. See also [this](https://stackoverflow.com/questions/46770250/how-to-compare-two-arrays-for-identical-objects?noredirect=1#comment80487101_46770250) try if you don't want `.find()`. – dhilt Oct 16 '17 at 13:04
  • It is closed because @Cerbrus wrongly classified it as a duplicate and forced you to post the answer in another question, thus depriving me of the opportunity to properly thank you by accepting your answer... At least I upvoted your answer in the other thread. – Flame_Phoenix Oct 16 '17 at 13:05
  • I also added a link to this post. Thanks! – dhilt Oct 16 '17 at 13:06
  • The problem is literally the same. The short-circuit requirement isn't really a significant difference. – Cerbrus Oct 16 '17 at 13:09
  • Not if you have a machine with infinity memory. Who are you to say what is and what is not a significant difference? I am the OP, and I made it clear that this was a significant difference for me. *I did that twice*. You made a mistake in classifying this as a duplicate and now your ego is simply justifying the unjustifiable. If you were to start a conversation with me and wrongly deduce such conclusion, I could understand it, but you didn't even do that. You just put my question into the DUP bag and then didn't allow me nor anyone else to confront your decision. – Flame_Phoenix Oct 18 '17 at 08:14
  • @Flame_Phoenix: if you wish to contest a duplicate classification, you can post on Meta](https://meta.stackoverflow.com/). Keep it calm and level-headed, and realise that either of you may have made a wrong assessment, and you'll be fine. – halfer Oct 23 '17 at 22:09

0 Answers0