1

I have the following associative array of objects:

[
    0: {
        "score": "value2",
        "number": "1",
        "finalScore": "-1"
    },

    1: {
        "score": "value3",
        "number": "2",
        "finalScore": "5"
    },

    2: {
        "score": "value4",
        "number": "2",
        "finalScore": "5"
    },

    3: {
        "score": "value5",
        "number": "3",
        "finalScore": "-1"
    }
]

Please, have in mind the following format is the prettified JSON string on the browser, after returning it from PHP through an echo json_encode($result)

I need to filter it based on the number property value, in order to remove all duplicates with the same value for the number property except the first one. This means that if two or more objects share the same value for number, only the first one should remain.

Given this explanation, the filtered array from the example above would result on:

[
    0: {
        "score": "value2",
        "number": "1",
        "finalScore": "-1"
    },

    1: {
        "score": "value3",
        "number": "2",
        "finalScore": "5"
    },

    2: {
        "score": "value5",
        "number": "3",
        "finalScore": "-1"
    }
]

I have made several attempts, the closest I've been is this funcion:

function array_iunique($array) {
    $lowered = array_map('strtolower', $array);
    return array_intersect_key($array, array_unique($lowered));
}
Biomehanika
  • 1,530
  • 1
  • 17
  • 45
  • 1
    what have you tried, show us your best attempt(code), you might be closer to a solution than you think. Please read [ask]. – berend May 02 '21 at 08:01
  • @berend sure, I've edited with my closest attempt. Thank you. – Biomehanika May 02 '21 at 08:03
  • https://stackoverflow.com/questions/25561707/get-unique-value-of-one-attribute-from-array-of-associative-arrays maybe this one can help you – Jayesh Nai May 02 '21 at 08:08
  • 2
    Define "except the first one" (that seems a pretty important bit). Does that mean if the key `number: 1` is duplicated, its duplicate shouldn't be removed? Or whichever key is at position 0 in the array? Also, what structure are you actually working with? Is that an array of arrays, objects or JSON strings? – El_Vanja May 02 '21 at 08:10
  • Thank you @El_Vanja, just edited the question detailing that info. – Biomehanika May 02 '21 at 08:13
  • I am about to try @JayeshNai – Biomehanika May 02 '21 at 08:15
  • 1
    Are you certain these are PHP objects? Calling `strtolower` on an actual object should be throwing a warning. – El_Vanja May 02 '21 at 08:18
  • I am about to check both the array and positions type @El_Vanja, I'm unexperienced on PHP and there's a chance of typing misinformation... – Biomehanika May 02 '21 at 08:24
  • Honestly I amd catching the PHP response from a json_encode return on the browser – Biomehanika May 02 '21 at 08:25
  • So that's actually a JSON string, prettified. Can you show the code that builds this array before you encode it? Maybe this can be solved at the root, instead of having to filter after it's already created. – El_Vanja May 02 '21 at 08:27
  • @El_Vanja, I've made two `gettype()` showing "array" for the array containing the objects, and "object" for the contained objects. The array comes from a SQL select query (wordpress), and before I try to remove duplicates I've made an array_map and array_filter. If there's a way I can provide you with a clear output let me know please. Thank you vey much. – Biomehanika May 02 '21 at 08:34
  • Also sounds like it could be solved at the query level. – El_Vanja May 02 '21 at 09:03

2 Answers2

0

Sounds pretty straight forward to me: you iterate over the input array and accept the elements only if the output does not yet contain such a candidate...

<?php
$input = json_decode(<<<EOT
[
    {
        "score": "value2",
        "number": "1",
        "finalScore": "-1"
    }, {
        "score": "value3",
        "number": "2",
        "finalScore": "5"
    }, {
        "score": "value4",
        "number": "2",
        "finalScore": "5"
    }, {
        "score": "value5",
        "number": "3",
        "finalScore": "-1"
    }
]
EOT);

$output = [];
array_walk($input, function ($entry) use (&$output) {
    if (!array_key_exists($entry->number, $output)) {
        $output[$entry->number] = $entry;
    }
}); 

print_r(array_values($output));

The output obviously is:

Array
(
    [0] => stdClass Object
        (
            [score] => value2
            [number] => 1
            [finalScore] => -1
        )
    [1] => stdClass Object
        (
            [score] => value3
            [number] => 2
            [finalScore] => 5
        )
    [2] => stdClass Object
        (
            [score] => value5
            [number] => 3
            [finalScore] => -1
        )
)
arkascha
  • 41,620
  • 7
  • 58
  • 90
  • I am about to try, thank you. Please have in mind I posted the prettified JSON string from the browser, after returning it through an echo json_encode($result). I have updated the question explaining this. Sorry for the mess, I am quite unexperienced on PHP – Biomehanika May 02 '21 at 08:40
  • 1
    It does not matter where that array of objects comes from. I used the JSON notation only because it intuitively reflects the data you proposed in your question. – arkascha May 02 '21 at 08:42
  • 1
    You can. The `json_decode()` is not part of what I suggest. It only prepares the input data for the demonstration. If you already have an array then fine, just use that. Concentrate on the middle part of my example... – arkascha May 02 '21 at 08:43
0

Simple approache:

  1. Firstly, convert data from json format to array of scores using json_decode with second args true.
  2. Secondly, create three variable one for output $scores_filtered, second to keep track only unique numbers and $index to keep the order ascending of $scores_filtered array.
  3. Thirdly, iterate over the array of score and check if the number first time occures (meaning doesn't exist in array $unique_numbers) if So, store it in $unique_numbers. get that score and store in $scores_filtered array.
$json = '[{
        "score": "value2",
        "number": "1",
        "finalScore": "-1"
    },{
        "score": "value3",
        "number": "2",
        "finalScore": "5"
    },{
        "score": "value4",
        "number": "2",
        "finalScore": "5"
    },{
        "score": "value5",
        "number": "3",
        "finalScore": "-1"
    }
]';
$scores = json_decode($json, true);
$scores_filtered = [];
$unique_numbers = [];
$index = 0;
for($i = 0; $i < count($scores); $i++) {
    $score = $scores[$i];
    if(!in_array($score['number'], $unique_numbers)){
        $unique_numbers[] = $score['number'];
        $scores_filtered[$index]["score"] = $score["score"];
        $scores_filtered[$index]["number"] = $score["number"];
        $scores_filtered[$index]["finalScore"] = $score["finalScore"];
        $index += 1;
    }
}

Output:

echo "<pre>";
print_r(json_encode($scores_filtered, JSON_PRETTY_PRINT));
/*
[
    {
        "score": "value2",
        "number": "1",
        "finalScore": "-1"
    },
    {
        "score": "value3",
        "number": "2",
        "finalScore": "5"
    },
    {
        "score": "value5",
        "number": "3",
        "finalScore": "-1"
    }
]
*/
XMehdi01
  • 5,538
  • 2
  • 10
  • 34