Search code examples
laraveleloquentlaravel-collection

Calculate total number of duplicate values in two separate collections in Laravel?


I have two collections, C1 and C2. Values in both these collections coming from the same model. The structure of the collection is as:

id, sender_id, receiver_id, status

an instance of c1 is as:

  #items: array:3 [▼
    0 => {#1417 ▼
      +"id": 21
      +"sender_id": 19
      +"receiver_id": 13
      +"status": "added"
      +"created_at": "2022-08-09 19:28:24"
      +"updated_at": "2022-08-09 19:28:24"
    }
    1 => {#1416 ▼
      +"id": 22
      +"sender_id": 19
      +"receiver_id": 11
      +"status": "added"
      +"created_at": "2022-08-09 19:28:28"
      +"updated_at": "2022-08-09 19:28:28"
    }
    2 => {#1419 ▼
      +"id": 23
      +"sender_id": 19
      +"receiver_id": 12
      +"status": "added"
      +"created_at": "2022-08-09 19:28:32"
      +"updated_at": "2022-08-09 19:28:32"
    }
  ]
  #escapeWhenCastingToString: false
}

and instance of C2 is:

  #items: array:3 [▼
    0 => {#1407 ▼
      +"id": 24
      +"sender_id": 18
      +"receiver_id": 13
      +"status": "added"
      +"created_at": "2022-08-09 19:28:52"
      +"updated_at": "2022-08-09 19:28:52"
    }
    1 => {#1398 ▼
      +"id": 25
      +"sender_id": 18
      +"receiver_id": 11
      +"status": "added"
      +"created_at": "2022-08-09 19:28:57"
      +"updated_at": "2022-08-09 19:28:57"
    }
    2 => {#1412 ▼
      +"id": 26
      +"sender_id": 18
      +"receiver_id": 12
      +"status": "added"
      +"created_at": "2022-08-09 19:29:01"
      +"updated_at": "2022-08-09 19:29:01"
    }
  ]
  #escapeWhenCastingToString: false
}

The function where this is all being done is:

    public function mutualFriend(User $user)
    {
        $C1 = DB::table('friendships')->where('sender_id', auth()->id())->where('status', 'added')->get();
        $C2 = DB::table('friendships')->where('sender_id', $user->id)->where('status', 'added')->get();
//3 should be calculated here
    }

I want to calculate all the receiver_ids that are common in both C1 and C2 collections. In the above example, the count should be three as there are three same receiver_ids in both C1 and C2 collections.

As far as my personal findings are concerned, I tried on stack-overflow but all the answers were related to finding duplicate values in the one collection only. I tried searching other platforms like laracast, codegreeper, etc but couldn't find my specific answer. A solution is linked here but that solution worked for simple collection. My problem contains array of collection that requires pluck() method


Solution

  • Given the Data:

    $c1 = collect([
      (object)[
        "id" => 21,
        "sender_id" => 19,
        "receiver_id" => 13,
        "status" => "added",
        "created_at" => "2022-08-09 19:28:24",
        "updated_at" => "2022-08-09 19:28:24",
      ],
      (object)[
        "id" => 22,
        "sender_id" => 20,
        "receiver_id" => 11,
        "status" => "added",
        "created_at" => "2022-08-09 19:28:28",
        "updated_at" => "2022-08-09 19:28:28",
      ],
      (object)[
        "id" => 23,
        "sender_id" => 21,
        "receiver_id" => 12,
        "status" => "added",
        "created_at" => "2022-08-09 19:28:32",
        "updated_at" => "2022-08-09 19:28:32",
      ]
    ]);
    
    $c2 = collect([
      (object)[
        "id" => 24,
        "sender_id" => 18,
        "receiver_id" => 13,
        "status" => "added",
        "created_at" => "2022-08-09 19:28:52",
        "updated_at" => "2022-08-09 19:28:52",
      ],
      (object)[
        "id" => 25,
        "sender_id" => 18,
        "receiver_id" => 11,
        "status" => "added",
        "created_at" => "2022-08-09 19:28:57",
        "updated_at" => "2022-08-09 19:28:57",
      ],
      (object)[
        "id" => 26,
        "sender_id" => 18,
        "receiver_id" => 12,
        "status" => "added",
        "created_at" => "2022-08-09 19:29:01",
        "updated_at" => "2022-08-09 19:29:01",
      ]
    ]);
    

    You can use the ->intersect() method of Laravel's Collections to generate a new Collection of "shared" properties. But first, you'll need to pluck() it for comparison:

    $mutualSenders = $c1->pluck('receiver_id')->intersect($c2->pluck('receiver_id'));
    

    Which results in this Collection:

    Illuminate\Support\Collection {#3505
      all: [
        13,
        11,
        12,
      ],
    }
    

    Then, you can simply apply ->count() to get the number:

    $mutualSendersCount = $c1->pluck('receiver_id')->intersect($c2->pluck('receiver_id'))->count();
    // 3
    

    For a list of all the available Collection methods, please check here:

    https://laravel.com/docs/9.x/collections#available-methods

    Used Methods Reference:

    https://laravel.com/docs/9.x/collections#method-pluck

    https://laravel.com/docs/9.x/collections#method-intersect

    https://laravel.com/docs/9.x/collections#method-count


    Edit: Applied directly to your code:

    public function mutualFriend(User $user) {
      return DB::table('friendships')->where('sender_id', auth()->id())->where('status', 'added')
      ->pluck('receiver_id')
      ->intersect(DB::table('friendships')->where('sender_id', $user->id)->where('status', 'added')->pluck('receiver_id'));
    }