How to find the position of key value in an array - php

I have an array with user id and transaction details sorted based on transaction. Now I need to find the position of key value
Array
(
[0] => Array
(
[userid] => 3
[transaction] => 1878
)
[1] => Array
(
[userid] => 2
[transaction] => 416
)
[2] => Array
(
[userid] => 5
[transaction] => 353
)
[3] => Array
(
[userid] => 4
[transaction] => 183
)
)
When I give user id 4 then it should return 3

First, use array_column() to fetch all userid, then use array_search() to retrieve array key.
$searchId = 4;
echo array_search( $searchId, array_column($array, 'userid') ) );

I might just iterate the outer array here and the check the key values:
$pos = -1;
for ($i = 0; $i < count($array); $i++) {
if ($array[$i]['userid'] == 4) {
$pos = $i;
}
}
if ($pos == -1) {
echo "user not found";
}
else {
echo "user found at position " . $pos;
}

I prefer Calos's answer.
The code below imitates JavaScript's Array.prototype.findIndex to achieve what you need. Using this approach you can have more flexibility in searching the array by using a callback function, similar to how JavaScript has done it.
You can also easily reuse it in other parts of your code.
$data = [
[
'userid' => 3,
'transaction' => 1878
],
[
'userid' => 2,
'transaction' => 416
],
[
'userid' => 5,
'transaction' => 353
],
[
'userid' => 4,
'transaction' => 183
]
];
function findIndex($array, $method){
foreach($array as $index => $value){
if ($method($value, $index, $array) === true){
return $index;
}
}
}
echo findIndex($data, function($arr){
return $arr['userid'] == 5;
});

It's trivial to build your own map:
<?php
$items =
[
'foo' =>
[
'id' => 23,
],
'bar' =>
[
'id' => 47
]
];
foreach($items as $k=>$v)
$ids_keys[$v['id']] = $k;
echo $ids_keys[47];
Output:
bar

Related

How to count specific value from array PHP?

I have an multidimensional array and I need to count their specific value
Array
(
[0] => Array
(
[Report] => Array
(
[id] => 10
[channel] => 1
)
)
[1] => Array
(
[Report] => Array
(
[id] => 92
[channel] => 0
)
)
[2] => Array
(
[Report] => Array
(
[id] => 18
[channel] => 0
)
)
[n] => Array
)
I need to get output like that: channel_1 = 1; channel_0 = 2 etc
I made a function with foreach:
foreach ($array as $item) {
echo $item['Report']['channel'];
}
and I get: 1 0 0 ... but how can I count it like: channel_1 = 1; channel_0 = 2, channel_n = n etc?
Try this. See comments for step-by-step explanation.
Outputs:
array(2) {
["channel_1"]=>
int(1)
["channel_0"]=>
int(2)
}
Code:
<?php
// Your input array.
$a =
[
[
'Report' =>
[
'id' => 10,
'channel' => 1
]
],
[
'Report' =>
[
'id' => 92,
'channel' => 0
]
],
[
'Report' =>
[
'id' => 18,
'channel' => 0
]
]
];
// Output array will hold channel_N => count pairs
$result = [];
// Loop over all reports
foreach ($a as $report => $values)
{
// Key takes form of channel_ + channel number
$key = "channel_{$values['Report']['channel']}";
if (!isset($result[$key]))
// New? Count 1 item to start.
$result[$key] = 1;
else
// Already seen this, add one to counter.
$result[$key]++;
}
var_dump($result);
/*
Output:
array(2) {
["channel_1"]=>
int(1)
["channel_0"]=>
int(2)
}
*/
You can easily do this without a loop using array_column() and array_count_values().
$reports = array_column($array, 'Report');
$channels = array_column($reports, 'channel');
$counts = array_count_values($channels);
$counts will now equal an array where the key is the channel, and the value is the count.
Array
(
[1] => 1
[0] => 2
)

Merge arrays in an array and add values

I need to take an array like this:
Array
(
[0] => Array
(
[county_code] => 54045
[count] => 218
)
[1] => Array
(
[county_code] => 54045
[count] => 115
)
[2] => Array
(
[county_code] => 54051
[count] => 79
)
)
And merge all arrays with the same county_code adding the count, like this:
Array
(
[0] => Array
(
[county_code] => 54045
[count] => 333
)
[1] => Array
(
[county_code] => 54051
[count] => 79
)
)
There will be multiple instances of multiple county codes.
Can anyone point me in the right direction?
Try this out:
// your example array
$array = [
[
"county_code" => 54045,
"count" => 218
],
[
"county_code" => 54045,
"count" => 115
],
[
"county_code" => 54051,
"count" => 79
]
];
// intrim step to collect the count.
$intrimArray = [];
foreach( $array as $data ){
$countyCode = $data["county_code"];
if (!$intrimArray[$countyCode]) {
$intrimArray[$countyCode] = $data["count"];
} else {
$intrimArray[$countyCode] = $intrimArray[$countyCode] + $data["count"];
}
}
// build the final desired array using interim array.
$finalArray = [];
foreach($intrimArray as $countyCode => $totalCount) {
array_push($finalArray, [
"county_code" => $countyCode,
"count" => $totalCount
]);
}
var_dump($finalArray);
As promised:
<?php
$initial_array = [
['country_code' => 54045, 'count' => 218],
['country_code' => 54045, 'count' => 115],
['country_code' => 54051, 'count' => 79],
];
$synth = [];
foreach ($initial_array as $sa) { # $sa: subarray
if (!isset($synth[$sa['country_code']])) {
$synth[$sa['country_code']] = 0;
}
$synth[$sa['country_code']] += $sa['count'];
}
print_r($synth); # Synthesis array: keys are country codes, values are cumulative counts.
# If you need the same format for both the initial and synthesis arrays, then continue with this:
$synth2 = [];
foreach ($synth as $k => $v) {
$synth2[] = ['country_code' => $k, 'count' => $v];
}
print_r($synth2);
?>
A fiddle for this code: https://3v4l.org/M8tkb
Best regards

Adding to another array with triming few characters from string

$data has
stdClass Object
(
[class] => srt-fields
[rules_field_1] => 1
[rules_condition_1] => 0
[rules_value_1] => text
[rules_field_2] => 3
[rules_condition_2] => 1
[rules_value_2] => another_text
...
)
Now I have another array $newdata, I need to have index $newdata['rules'] so that it should be something like:
$newdata['rules'] => array(
[field] => 1,
[condition] => 0,
[value] => text
),
array(
[field]=> 3,
[condition] =>1,
[value] => another_text
),
...
Thanks!
You could iterate over the properties of an object like an array:
$newdata['rules']=[];
foreach ($data as $key => $value) {
if (substr($key,0,6)=='rules_') {
// split key using '_'
$parts = explode('_',$key);
// get the 'name'
$name = $parts[1] ;
// get the index (-1 to be 0 based)
$idx = $parts[2] - 1;
// store data in new array
$newdata['rules'][$idx][$name] = $value;
}
}
print_r($newdata);
Outputs:
Array
(
[rules] => Array
(
[0] => Array
(
[field] => 1
[condition] => 0
[value] => text
)
[1] => Array
(
[field] => 3
[condition] => 1
[value] => another_text
)
)
)
Here is working code,
$data = [
"class" => "srt-fields",
"rules_field_1" => "1",
"rules_condition_1" => "0",
"rules_value_1" => "text",
"rules_field_2" => "3",
"rules_condition_2" => "1",
"rules_value_2" => "another_text",
];
$result = [];
foreach ($data as $k => $v) {
$num = filter_var($k, FILTER_SANITIZE_NUMBER_INT);
if (!empty($num)) {
$result['rules'][$num][(str_replace(['rules_', '_'], '', preg_replace('/[0-9]+/', '', $k)))] = $v;
}
}
$result['rules'] = array_values($result['rules']);
print_r($result);
str_replace — Replace all occurrences of the search string with the replacement string
filter_var — Filters a variable with a specified filter
preg_replace — Perform a regular expression search and replace
str_replace — Replace all occurrences of the search string with the replacement string
Here is working demo.
Definitely do not use regular expressions for this task -- because it is unnecessary resource overhead. Explode the keys on underscores, and use the individual components to construct the multi-level keys in your output array.
Code: (Demo)
$data = (object)[
"class" => "srt-fields",
"rules_field_1" => "1",
"rules_condition_1" => "0",
"rules_value_1" => "text",
"rules_field_2" => "3",
"rules_condition_2" => "1",
"rules_value_2" => "another_text"
];
foreach ($data as $key => $value) {
$bits = explode('_',$key); // this will produce a 1-element array from `class` and a 3-element array from others
if (isset($bits[2])) { // if element [2] exists, then process the qualifying data
$newdata[$bits[0]][$bits[2]-1][$bits[1]] = $value;
// ^^- make zero based
}
}
var_export($newdata);
Output:
array (
'rules' =>
array (
0 =>
array (
'field' => '1',
'condition' => '0',
'value' => 'text',
),
1 =>
array (
'field' => '3',
'condition' => '1',
'value' => 'another_text',
),
),
)
I am using -1 to make the output keys resemble a zero-based / indexed array. If your fields might not be consecutively ordered, you can remove the -1 and write $newdata['rules'] = array_values($newdata['rules']); after the loop.
$i = 0;
$j = 0;
foreach($data as $key=>$value){
if($j == 0)
{
$newdata['rules'][$i]['field'] = $value;
}
if($j == 1)
{
$newdata['rules'][$i]['condition'] = $value;
}
if($j == 2)
{
$newdata['rules'][$i]['value'] = $value;
$i++;
}
$j++;
if($j > 2)
{
$j = 0;
}
}
You can try this code. Please ignore syntax error as I have not tried this code but it should give you the result.

PHP Sort array joint positions

I have an array of players each with a number of points.
I can easily sort the array in order of the points using a custom usort function.
But when two players have the same amount of points I need to rank them as the same winning position within the list.
E.g.
Nick - 25
Tom - 18
Chris - 18
Dave - 16
James - 8
In this case the data that I require would be
Nick - 1st
Tom - (joint) 2nd
Chris - (joint) 2nd
Dave 3rd
James 4th
So players with equal scores are designated the same ranking position.
What is the best way of calculating these positions?
Thanks!
This will give you what you want with an additional fix: if you have two players in position 2 the next player should be in position 4. If you don't want this additional fix move $count++; into the if statement.
$count = 0;
$position = 0;
$last_score = -1;
foreach ($players as $player)
{
$count++;
if ($last_score !== $player->score)
{
$position = $count;
}
$player->position = $position;
$last_score = $player->score;
}
I think the following code would do the job as required:
$scores = array('Nick'=>25,'Tom'=>18,'Chris'=>18,'Dave'=>16, 'James'=> 8,);
$scores_numbers = array_unique(array_values($scores));
$scores_counter = array_count_values($scores);
$pos = 1;
foreach($scores_numbers as $num) {
foreach($scores as $name=>$score) {
if($num == $score) {
if($scores_counter[$score] > 1) {
echo "$name - (joint) $pos<br />";
} else {
echo "$name - $pos<br />";
}
}
}
$pos++;
}
I have updated the code to avoid the duplicating output.
If you are retrieving player stats from DB then below code can be useful to rank them :
<?php
$players = [
['name' => 'Ash',
'point' => 0
],
['name' => 'Bob',
'point' => 10
],
['name' => 'Cane',
'point' => 0
],
['name' => 'Dory',
'point' => 6
],
['name' => 'Efat',
'point' => 6
],
];
usort($players, function($v1, $v2){
return $v2['point'] - $v1['point'];
});
$ranking = [];
$currentPosition = 0;
$heighestPoint = PHP_INT_MIN;
foreach($players as $player){
if($heighestPoint !== $player['point']){
$currentPosition++;
$heighestPoint = $player['point'];
}
$ranking[$currentPosition][] = $player;
}
print_r($ranking);
Output :
Array
(
[1] => Array
(
[0] => Array
(
[name] => Bob
[point] => 10
)
)
[2] => Array
(
[0] => Array
(
[name] => Dory
[point] => 6
)
[1] => Array
(
[name] => Efat
[point] => 6
)
)
[3] => Array
(
[0] => Array
(
[name] => Ash
[point] => 0
)
[1] => Array
(
[name] => Cane
[point] => 0
)
)
)
May it helps
/*Below array must be sorted */
$a1=array("Nick"=>25,"Tom"=>18,"Chris"=>18,"Dave"=>16,"James"=>8);
$makeUnique=array_unique($a1);
$makeUnique=array_values($makeUnique);
$pArr=array_map('setPosition',$a1);
print_r($pArr);
function setPosition($a){
Global $makeUnique;
return array_search($a,$makeUnique)+1;
}
OUT PUT
Array ( [Nick] => 1 [Tom] => 2 [Chris] => 2 [Dave] => 3 [James] => 4 )
I used usort to sort assoc array
$players = [["name" => "Nick" , "score" => 25] , ["name" => "Tom" , "score" => 18] , ["name" => "chris" , "score" => 18] , ["name" => "dave" , "score" => 16 ] , ["name" => "james" , "score" => 8]];
usort($players , function($a , $b) {return $b["score"] - $a["score"];} );
var_dump($players);
$lastScore = null;
$pos = 1;
foreach($players as $player)
{
if($lastScore != null && $lastScore == $player["score"])
echo $pos-1 . " - " . $player["name"] . '<br/>';
else
echo $pos++ . " - " . $player["name"] . '<br/>';
$lastScore = $player["score"];
}
checkout this code in teh playground

PHP Array - Count Partial Duplicates

I have an array of objects.
I want to count the total number of array items where two values are an exact match.
Array
(
[0] => stdClass Object
(
[Job] => stdClass Object
(
[ID] => 123
[Line] => Shirt
[Color] => Blue
)
)
[1] => stdClass Object
(
[Job] => stdClass Object
(
[ID] => 456
[Line] => Jeans
[Color] => Blue
)
)
[2] => stdClass Object
(
[Job] => stdClass Object
(
[ID] => 789
[Line] => Jeans
[Color] => Blue
)
)
)
In this simplified example I want to Count that there are 2 array items that have Blue Jeans.
Probably the best approach is to use an index as one would do inside a database:
<?php
$json = <<<JSON
[
{"Job":{"ID":123,"Line":"Shirt","Color":"Blue"}},
{"Job":{"ID":456,"Line":"Jeans","Color":"Blue"}},
{"Job":{"ID":789,"Line":"Jeans","Color":"Blue"}}
]
JSON;
$data = json_decode($json);
$index = [];
$counter = 0;
array_walk($data, function(\stdClass $entry) use (&$index, &$counter) {
$key = $entry->Job->Line . '|' . $entry->Job->Color;
if (!in_array($key, $index)) {
$index[] = $key;
} else {
$counter++;
}
});
print_r($counter);
The output obviously is:
1
Just use a good old loop.
$count = 0; //Initialize the number of matches to 0
//Loop through each item (obviously)
foreach($array as $item) {
//Check if the required properties match.
//If they do, increment $count by 1
if($item->Job->Line=="Jeans" && $item->Job->Color=="Blue") ++$count;
}
//Do whatever is required with the value of $count
Here is another approach using simple recursion. You can set the number of matches desired, and it will find matches for any property (nothing is fixed). I wrapped it in a class to keep everything contained:
<?php
class MatchFind {
// This can be set to any number of matches desired
const ELEMENTS_TO_FIND = 2;
public static function count ($aObjs) {
// Cannot compare elements unless there are 2
if (sizeof($aObjs) <= 1) {
return 0;
}
// Get the top element from the array
$oTop = array_shift($aObjs);
$aTopProps = (array) $oTop->Job;
// Get the number of matches, moving from end to start,
// removing each match from the array
$iMatchObjs = 0;
for ($n = sizeof($aObjs); $n > 0; $n--) {
$oCompare = $aObjs[$n-1];
$iMatch = 0;
foreach ((array) $oCompare->Job as $sKey => $sValue) {
if (isset($aTopProps[$sKey]) && $aTopProps[$sKey] === $sValue) {
++$iMatch;
}
}
if ($iMatch >= self::ELEMENTS_TO_FIND) {
unset($aObjs[$n-1]);
++$iMatchObjs;
}
}
reset($aObjs);
return ($iMatchObjs + self::count($aObjs));
}
}
// Declare the objects
$aAllObjs = [
(object)[ 'Job' => (object)['ID' => 123,
'Line' => 'Shirt',
'Color' => 'Blue'] ],
(object)[ 'Job' => (object)['ID' => 456,
'Line' => 'Jeans',
'Color' => 'Blue'] ],
(object)[ 'Job' => (object)['ID' => 789,
'Line' => 'Jeans',
'Color' => 'Blue'] ],
];
echo MatchFind::count($aAllObjs);

Categories