Roshan Bhumbra Roshan Bhumbra -4 years ago 112
PHP Question

Find array elements with matching values

I have an array which contains multiple objects, some of these objects may have matching values for

lap_time
, in this example element
1
, and
2
have matching values:

Array
(
[0] => stdClass Object
(
[id] => 1
[recorded_time] => 00:51:55.000000
[corrected_time] => 00:45:32.456140
[lap_time] => 00:09:06.491228
[laps] => 5
[code] =>
[sail_no] => 4931
[class] => SOLO
[helm_fname] => [Removed]
[helm_lname] => [Removed]
[crew_1_fname] =>
[crew_1_lname] =>
[crew_2_fname] =>
[crew_2_lname] =>
[modified_time] =>
[created_time] => 2017-02-19 17:53:48
[created_fname] => Admin
[created_lname] => istrator
[modified_fname] =>
[modified_lname] =>
[points] => 1
)

[1] => stdClass Object
(
[id] => 21
[recorded_time] => 00:50:07.000000
[corrected_time] => 00:45:56.186984
[lap_time] => 00:09:11.237397
[laps] => 5
[code] =>
[sail_no] => 67173
[class] => LASER
[helm_fname] => [Removed]
[helm_lname] => [Removed]
[crew_1_fname] =>
[crew_1_lname] =>
[crew_2_fname] =>
[crew_2_lname] =>
[modified_time] => 2017-02-22 10:51:58
[created_time] => 2017-02-19 18:40:58
[created_fname] => Admin
[created_lname] => istrator
[modified_fname] =>
[modified_lname] =>
[points] => 2
)

[2] => stdClass Object
(
[id] => 2
[recorded_time] => 00:50:07.000000
[corrected_time] => 00:45:56.186984
[lap_time] => 00:09:11.237397
[laps] => 5
[code] =>
[sail_no] => 52441
[class] => LASER
[helm_fname] => [Removed]
[helm_lname] => [Removed]
[crew_1_fname] =>
[crew_1_lname] =>
[crew_2_fname] =>
[crew_2_lname] =>
[modified_time] => 2017-02-22 10:51:58
[created_time] => 2017-02-19 18:40:58
[created_fname] => Admin
[created_lname] => istrator
[modified_fname] =>
[modified_lname] =>
[points] => 3
)


If any objects have matching values for
lap_time
, the matching objects need to have their points averaged.

This is what I started doing, but I realized this is probably not the best way to go about doing this. The
break_race_ties
method is not finished.

<?php

class Results_calculations_model
{
public
function race_points($results)
{
$points = 0;
$results_with_points = array();

foreach ($results AS $result) {
//increment points by one for each position
$points++;
$result->points = $points;

//add result back to array;
$results_with_points[] = $result;
}


$results_with_points = $this->break_race_ties($results_with_points);

return $results_with_points;
}

protected
function break_race_ties($results)
{
$previous_time = 0;
$ties = array();

foreach ($results AS $result) {

if ($previous_time === $result->lap_time) {
$ties['points'][] = $result->points;
$ties['id'][] = $result->id;

$average_points = $this->average_array_values($ties['points']);
}


$previous_time = $result->lap_time;
}
}

protected
function average_array_values($values)
{
$number_of_elements = count($values);
$total_points = array_sum($values);

return $total_points / $number_of_elements;
}
}


Can you suggest any functions that might help me with this, or a code example of what to do

Answer Source

Here's what I ended up doing

     /**
     * Find the amount of points each boat in the race should have
     *
     * This method will assign points and, in the event of a tie,
     * average them.
     *
     * @param $results
     *
     * @return array
     */
    public function race_points($results)
    {
        $points = 0;
        $results_with_points = array();

        //assign incremental amounts of points to each boat
        foreach ($results AS $result) {
            //increment points by one for each position
            $points++;
            $result->points = $points;

            //add result back to array;
            $results_with_points[] = $result;
        }

        $results_with_points = $this->break_race_ties($results_with_points);

        return $results_with_points;
    }

    /**
     * Find any ties and average their points
     *
     * @param $results
     *
     * @return mixed
     */
    protected function break_race_ties($results)
    {
        $ties = $this->find_race_ties($results);

        if (!empty($ties)) {
            //looks like there are tied results, average the points and assign them

            foreach ($ties AS $tie) {
                $points = $this->average_array_values($tie['points']);

                foreach ($tie['id'] AS $id) {
                    $results[ $id ]->points = $points;
                }
            }
        }

        return $results;
    }

    /**
     * Determine if any ties exist and get some information about them
     *
     * Finds any existing ties in the array of results and gets,
     * their element id and the points of each tying boat.
     *
     * @param $results
     *
     * @return array
     */
    protected function find_race_ties($results)
    {
        $previous_id = NULL;
        $previous_points = NULL;
        $previous_time = NULL;
        $ties = array();

        foreach ($results AS $id => $result) {

            if ($previous_time === $result->lap_time) {

                // Create empty array if required, so we don't push to NULL
                if (!isset($ties[ $previous_time ])) {
                    $ties[ $previous_time ]['points'] = array();
                    $ties[ $previous_time ]['id'] = array();
                }

                // Add each individual value to the array containing duplicates.
                // $previous_time is used as a key because it's identical when
                // it needs to be, meaning points and ids are grouped.
                array_push($ties[ $previous_time ]['points'], $result->points, $previous_points);
                array_push($ties[ $previous_time ]['id'], $id, $previous_id);

                // Remove duplicate values.
                $ties[ $previous_time ]['points'] = array_unique($ties[ $previous_time ]['points']);
                $ties[ $previous_time ]['id'] = array_unique($ties[ $previous_time ]['id']);
            }

            //Set these values for the next iteration to compare against
            $previous_id = $id;
            $previous_points = $result->points;
            $previous_time = $result->lap_time;
        }

        return $ties;
    }

    protected function average_array_values($values)
    {
        $number_of_elements = count($values);
        $total_points = array_sum($values);

        return $total_points / $number_of_elements;
    }
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download