4

I have 3 arrays for storing posts,comments, and likes.

These are the JSON strings:

//comments JSON (stores user and comment points)

$comments='[
    {
        "user": "5",
        "points": "12"
    },
    {
        "user": "2",
        "points": "1"
    },
    {
        "user": "3",
        "points": "1"
    }
]';

//likes(stores user and likes point)

$likes='[
    {
        "user": "1",
        "points": 7
    },
    {
        "user": "4",
        "points": 4
    },
    {
        "user": "3",
        "points": 1
    }
]';

//posts (stores user and post points)

$posts='[
    {
        "user": "1",
        "points": "6"
    },
    {
        "user": "3",
        "points": "2"
    },
    {
        "user": "2",
        "points": "1"
    }
]';

I convert these JSONs into arrays like this:

$comment_array  =   json_decode($comments,TRUE); 
$like_array     =   json_decode($likes,TRUE); 
$post_array     =   json_decode($posts,TRUE); 

//echo '<pre>';
//print_r($comment_array);
//print_r($like_array);
//print_r($post_array);
//echo '</pre>';

Now, I'm trying to sum these points and save the result in a new array. It's not mandatory that a user should have entries in all the three arrays. It depends on whether a user has made a comment, post or like.

function mergeArrays($filenames, $titles, $descriptions) {
    $result = array();

    foreach ( $filenames as $key=>$name ) {
        $result[] = array( 'filename' => $name, 'title' => $titles[$key], 'descriptions' => $descriptions[ $key ] );
    }

    return $result;
}

The above function can merge all the three arrays.

$merged= mergeArrays($comment_array, $like_array, $post_array);

echo '<pre>';
print_r($merged);
echo '</pre>';

However, each array after merging is stored as an index element.

How can I get a result something like this:

$result='[
    {
        "user": "1",
        "points": "13"
    },
    {
        "user": "2",
        "points": "2"
    },
    {
        "user": "3",
        "points": "4"
    },
    {
        "user": "4",
        "points": "4"
    },
    {
        "user": "5",
        "points": "12"
    }
]';

4 Answers 4

2

Considering your three arrays, this code will get you an array with: points, votes and diferent users.

Edit: Adding additional array and printing it to get the output desired by question.

$points = 0;

$uniqueUsers = array();
$votes = 0;
$users = 0;

$result = array();

//Comments
if (!empty($comment_array)) {
    foreach ($comment_array as $item) {

        if (!in_array($item['user'], $uniqueUsers)) {
            array_push($uniqueUsers, $item['user']);
            $result[$item['user']] = 0;
        }
        $votes ++;
        $result[$item['user']] += $item['points'];
    }
}

// Likes
if (!empty($like_array)) {
    foreach ($like_array as $item) {

        if (!in_array($item['user'], $uniqueUsers)) {
            array_push($uniqueUsers, $item['user']);
            $result[$item['user']] = 0;
        }
        $votes ++;
        $result[$item['user']] += $item['points'];
    }
}

// Posts
if (!empty($post_array)) {
    foreach ($post_array as $item) {

        if (!in_array($item['user'], $uniqueUsers)) {
            array_push($uniqueUsers, $item['user']);
            $result[$item['user']] = 0;
        }
        $votes ++;
        $result[$item['user']] += $item['points'];

    }
}


foreach ($result as $idUser=>$points) {
    echo "\n";
    echo "\n" . 'User: ' . $idUser;
    echo "\n" . 'Points: ' . $points;
}


$results = array('users'=> count($uniqueUsers), 'votes'=>$votes, 'points'=> $points);

//print_r($results);
Sign up to request clarification or add additional context in comments.

Comments

2

The solution using array_column, array_walk_recursive and array_values functions:

...
$comments = array_column($comment_array, 'points', 'user');
$likes = array_column($like_array, 'points', 'user');
$posts = array_column($post_array, 'points', 'user');

$list = [$comments, $likes, $posts];
$result = [];

array_walk_recursive($list, function($v, $k) use(&$result){
    if (key_exists($k, $result)){
        $result[$k]['points'] += $v;
    } else {
        $result[$k] = ['user' => $k, 'points' => $v];
    }
});
$result = array_values($result);

print_r($result);

The output:

Array
(
    [0] => Array
        (
            [user] => 5
            [points] => 12
        )

    [1] => Array
        (
            [user] => 2
            [points] => 2
        )

    [2] => Array
        (
            [user] => 3
            [points] => 4
        )

    [3] => Array
        (
            [user] => 1
            [points] => 13
        )

    [4] => Array
        (
            [user] => 4
            [points] => 4
        )
)

1 Comment

array_column() and array_walk_recursive() is not available in some versions of php. Nice method. I really like this. thank you.
0

Do the following to get one array with summed points:

$collections = array(
    'comments' => json_decode($comments,TRUE),
    'likes' => json_decode($likes,TRUE);,
    'posts' => json_decode($posts,TRUE),
);

$newArray = array();

foreach ($collections as $collection) {
    foreach ($collection as $user) {
        $newArray[$user->user] += $user->points;
    }
}

5 Comments

Nice try @Peter Correct your $collections array definition. So $collections = array() should be $collections = array( and your foreach value, so: foreach ($collections as $ollection)should be foreach ($collections as $collection)
It returns empty array even after correcting the typos. @Peter
@AmeliaEarheart I corrected my typos and fixed the point where I forgot json_decode returns an object instead of an array. It should be working now.
It still doesn't work. I tried this a few times. @Peter
"Do the following..." does very little to educate the OP and future researchers. Please improve your answer. You should take the time to test your answers before posting them, because this one will generate Notices and you shouldn't be suggesting solutions that do such things.
0

There are two important points to make if you want to learn the "best" way to handle these types of operations.

  1. Don't use iterated in_array() calls when isset() can be used instead. This is because isset() is much more efficient than in_array().

  2. Use temporary keys to identify duplicate occurrences, then re-index your results when finished -- usually with array_values(), but this time I used array_multisort() to re-order the results AND re-index.

Code: (Demo)

$merged = array_merge(json_decode($comments, true), json_decode($likes, true), json_decode($posts, true));
$result = [];
foreach ($merged as $entry) {
    if (!isset($result[$entry['user']])) {
        $result[$entry['user']] = $entry;
    } else {
        $result[$entry['user']]['points'] += $entry['points'];
    }
}
array_multisort(array_column($result, 'user'), $result);
// usort($result, function($a, $b) { return $a['user'] <=> $b['user']; });  
// array_multisort() will outperform `usort()` in this case.
echo json_encode($result);

Output:

[{"user":"1","points":13},{"user":"2","points":2},{"user":"3","points":4},{"user":"4","points":4},{"user":"5","points":"12"}]
  • Decode each array and merge them together into a multi-dimensional array.
  • Iterate each subarray and determine if it is the first occurrence of the user. If so, retain the entire subarray. If not, only increase the points tally within that subarray.
  • When the loop is finished, sort by user ascending.

This is clean, direct, and readable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.