Check same value in array - php

I have the following array:
$teams = [["id" => 1, "address" => "A1"],["id" => 2, "address" => "A1"],["id" => 3, "address" => "A2"]];
How can I check and get the teams with the same address? My output should be Team ID 1 and 2? Consider that I cannot use hard coded address. The data is dynamic and is coming from the database.
In php, laravel.
Thank you in advance!

Another way to do this is to use array_column() and array_count_values(). Then use array_filter() to remove elements with no duplicates:
$teams = [
["id" => 1, "address" => "A1"],
["id" => 2, "address" => "A1"] ,
["id" => 3, "address" => "A2"]
];
$dups = array_count_values(array_column($teams, 'address'));
$teams = array_filter($teams, function($item) use($dups) {
return $dups[$item['address']] > 1;
});
print_r($teams);
Outputs (reformatted):
Array
(
[0] => Array([id] => 1, [address] => A1)
[1] => Array([id] => 2, [address] => A1)
)

First you need to group by their address and then you can use array_filter() to truncate your array based on criteria:
<?php
$teams = [["id" => 1, "address" => "A1"],["id" => 2, "address" => "A1"],["id" => 3, "address" => "A2"]];
// Set a new array
$filtered = [];
// Loop the teams
foreach($teams as $v)
{
// Group the teams into their respective addresses
$filtered[$v['address']][] = $v;
}
// Filter out any address with 1 or fewer teams
$filtered = array_filter($filtered, function($v){
return count($v) > 1;
});
print_r($filtered);
// Now you can loop $filtered and display whatever you want
Output:
Array
(
[A1] => Array
(
[0] => Array
(
[id] => 1
[address] => A1
)
[1] => Array
(
[id] => 2
[address] => A1
)
)
)

Go through the array, remember which addresses are used by which team. When there is more than one team stored at a key (address), you found a duplicate:
<?php
$teams = [
["id" => 1, "address" => "A1"]
,["id" => 2, "address" => "A1"]
,["id" => 3, "address" => "A2"]
];
function findDuplicates($teams) {
$addresses = [];
foreach ($teams as $team) {
if (!isset($addresses[$team["address"]])) {
$addresses[$team["address"]] = [];
}
$addresses[$team["address"]][] = $team["id"];
}
foreach ($addresses as $address => $teamsHere) {
if (count($teamsHere) > 1) {
echo "Teams with same address (" . $address . "): " . join(",", $teamsHere) . "\n";
}
}
}
findDuplicates($teams);
Try it online!
Edit: a less "clunky" approach, using array_* functions:
<?php
$teams = [
["id" => 1, "address" => "A1"]
,["id" => 2, "address" => "A1"]
,["id" => 3, "address" => "A2"]
];
function findDuplicates($teams) {
$addresses = array_column($teams, "address");
$counts = array_count_values($addresses);
return array_filter($teams, function($team) use ($counts) { return $counts[$team["address"]] > 1; });
}
print_r(findDuplicates($teams));
Try it online!

Related

Finding value from another one in an array of arrays

I got the follwing array and I would like to retrieve the name by the id:
Array
(
[0] => Array
(
[id] => 1
[name] => john
)
[1] => Array
(
[id] => 2
[name] => mark
)
etc...
It is doable with double foreach loop and a conditional test, but is there a more elegant way?
Assuming that id is unique...
Long Version
$arr = [
['id'=1, 'name'='john'],
['id'=2, 'name'='mark'],
];
$lookup = [];
foreach($arr as $row) {
$id = $row['id'];
$name = $row['name'];
$lookup[$id] = $name;
}
// find name for id, 2
echo $lookup[2];
// ==> mark
Short Version
...see Progrock’s solution!
You can use array_column to map ids to names:
<?php
$arr = [
['id' => 1, 'name' => 'Rolf'],
['id' => 3, 'name' => 'Gary'],
['id' => 2, 'name' => 'Jimmy'],
];
$id_names = array_column($arr, 'name', 'id');
var_export($id_names);
print $id_names[3];
Output:
array (
1 => 'Rolf',
3 => 'Gary',
2 => 'Jimmy',
)Gary

How to group an array of associative arrays and declare custom keys?

Can someone help me with converting a php array in a grouped format? I am trying to group them by id. I would like to have the following array converted:
$Arr1=Array
(
0 => Array
(
"id" => "4123",
"test_number" => "1",
"sat_total" => "1050"
),
1 => Array
(
"id" => "4123",
"test_number" => "2",
"sat_total" => "1130"
),
2 => Array
(
"id" => "4123",
"test_number" => "3",
"sat_total" => "1120"
),
3 => Array
(
"id" => "5555",
"test_number" => "1",
"sat_total" => "1130"
),
4 => Array
(
"id" => "5555",
"test_number" => "2",
"sat_total" => "1160"
)
);
into this:
$Arr2=Array
(
0 => Array
(
"id" => "4123",
"Score1" => "1050",
"Score2" => "1130",
"Score3" => "1120"
),
1 => Array
(
"id" => "5555",
"Score1" => "1130",
"Score2" => "1160"
)
);
I have tried a little bit, but can't seem to find how to make it work.
You only need to iterate your rows of data, determine if each row is the first occurring id value or not, then either declare the initial values, or add a variably keyed element to the group. When the loop finishes, call array_values() to reindex the array (remove the temporary keys).
Code: (Demo)
$Arr1=[
["id" => "4123", "test_number" => "1", "sat_total" => "1050"],
["id" => "4123", "test_number" => "2", "sat_total" => "1130"],
["id" => "4123", "test_number" => "3", "sat_total" => "1120"],
["id" => "5555", "test_number" => "1", "sat_total" => "1130"],
["id" => "5555", "test_number" => "2", "sat_total" => "1160"]
];
foreach ($Arr1 as $set) {
if (!isset($result[$set['id']])) {
$result[$set['id']] = ['id' => $set['id'], 'Score1' => $set['sat_total']];
} else {
$result[$set['id']]['Score' . sizeof($result[$set['id']])] = $set['sat_total'];
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'id' => '4123',
'Score1' => '1050',
'Score2' => '1130',
'Score3' => '1120',
),
1 =>
array (
'id' => '5555',
'Score1' => '1130',
'Score2' => '1160',
),
)
This method will find the scores matching the $id.
It uses three array_intersects to match all the values correct.
This method will only loop the number of unique IDs, in your case two times.
Plus the times to create the score keys.
I do agree with what ggorlen says about the keys. That will also create a more efficient code.
$ids = array_column($Arr1, "id");
$sat = array_column($Arr1, "sat_total");
foreach(array_unique($ids) as $id){
$new[$id] = ["id" => $id];
$tmp = array_values(array_intersect_key($sat,array_intersect_key($Arr1, array_intersect($ids, [$id]))));
for($i=1;$i<=count($tmp);$i++) $new[$id]["Score" . $i] = $tmp[$i-1];
}
var_dump($new);
https://3v4l.org/ag3To
The output is an associative array with id as key.
You can use array_values if you want to make it indexed.
Just to show how much more efficient the code can be with one score array.
This is what it would look like:
$ids = array_column($Arr1, "id");
$sat = array_column($Arr1, "sat_total");
foreach(array_unique($ids) as $id){
$new[] = ["id" => $id, "scores" => array_values(array_intersect_key($sat,array_intersect_key($Arr1, array_intersect($ids, [$id]))))];
}
var_dump($new);
https://3v4l.org/mdA0W
$arr2 = [];
$i = 0;
$length = count($arr1);
do {
$builder = $arr1[$i];
// grab the first item from the original array
$builder = [
// set its initial properties
'id' => $arr1[$i]['id'],
'Score1' => $arr1[$i]['sat_total'],
];
// initialise the subsequent score number
$testNumber = 2;
// prepare to look ahead in the original array for a matching id
while (($i + 1) < $length) { // only look ahead if it is possible to
if ($arr1[$i + 1]['id'] == $builder['id']) {
// did you find a matching id? if so, let's set the subsequent score
$builder["Score$testNumber"] = $arr1[$i + 1]['sat_total'];
$testNumber++; // increase the next score number
$i++; // increase the original array index
} else {
// no luck? let's go forwards and set the next record
break;
}
}
$arr2[] = $builder; // set the built record into the new array
$i++; // move the pointer forwards
} while ($i < $length); // as long as there are items ahead
Not often you get to use a do-while. But it works :)
Feed it your original array $arr1 and $arr2 will be set.
It works by looking forward for matching ids. This solution assumes your original array is ordered by id! So unless you trust the input - don't use this solution!
Otherwise this is a simple, fast, and fairly readable solution to what looks to me like a school exercise?
If you want something that is safe, the other solutions here are suitable.
I'm not sure this structure is ideal--it seems like your keys "Score1", "Score2" etc would be best as an array like scores => [1050, 1130, ...] and it feels like the ids should be keys in the result array. But in any case, this gives your requested output:
$res = [];
foreach ($arr as $e) {
if (!array_key_exists($e['id'], $res)) {
$res[$e['id']] = [];
}
$res[$e['id']]["Score".(count($res[$e['id']])+1)] = $e['sat_total'];
}
$count = 0;
foreach ($res as $k => $v) {
$res[$k]['id'] = $k;
$res[$count++] = $res[$k];
unset($res[$k]);
}
print_r($res);
Output
Array
(
[0] => Array
(
[Score1] => 1050
[Score2] => 1130
[Score3] => 1120
[id] => 4123
)
[1] => Array
(
[Score1] => 1130
[Score2] => 1160
[id] => 5555
)
)
Note that I did two passes which is a little verbose, but taking the time to key in the data ids into the array in the first pass should improve a linear search through the array for each element into O(1) hashing, so I think it's worth the extra loop block.

create multimentional array in php

I try to create a multimentional array , I have a list of title
$array_title = array(
"fey palin" => 3,
"big theory" => 3,
"nyc through" => 3,
"jonas storm" => 3,
"bang theory" => 3,
"bang big" => 3,
"storm test" => 3,
"plain sahra" => 3,
"mind woolf" => 3,
"mind virginia" => 3
);
and I want to create a subarray if I find a link between two title for example big theory and bang theory are link by the word "theory"
Here my full code :
$array_title = array(
"fey palin" => 3,
"big theory" => 3,
"nyc through" => 3,
"jonas storm" => 3,
"bang theory" => 3,
"bang big" => 3,
"storm test" => 3 ,
"plain sahra" => 3,
"mind woolf" => 3,
"mind virginia" => 3
);
$new_array = array();
$i = 0;
foreach($array_title as $title => $value){
if(count($new_array) > 0){
$words = explode(' ',$title);
if(preg_grep ('/\b('.$words[0].'|'.$words[1].')\b/i', $new_array)){
$result = preg_grep ('/\b('.$words[0].'|'.$words[1].')\b/i', $new_array);
reset($result);
$first_key = key($result);
$new_array[$first_key][] = $title;
}else{
$new_array[$i] = $title;
}
}else{
$new_array[$i] = $title;
}
$i++;
}
it s seems i cant do that
$new_array[$first_key][] = $title;
I have an error which is:
[] operator not supported for strings
Edit : I changed my code a bit but I have some duplicate value
Here is my updated code
$array_title = array("fey palin" => 3 , "big theory" => 3 , "nyc through" => 3 ,
"bang theory" => 3 , "jonas storm" => 3 , "bang big" => 3 ,
"storm test" => 3 , "plain sahra" => 3 ,"mind woolf" => 3, "mind virginia" => 3);
$new_array = array();
foreach($array_title as $title => $value){
$words = explode(' ',$title);
if(count($new_array) > 0){
foreach($new_array as $key => $value){
if(preg_match('/\b('.$words[0].'|'.$words[1].')\b/', $key)){
$new_array[$key][$title] = $title;
}else{
if(count($value) > 0){
foreach($value as $val){
if(preg_match('/\b('.$words[0].'|'.$words[1].')\b/', $val)){
$new_array[$key][$title] = $title;
}
}
}else{
$new_array[$title] = array();
}
}
}
}else{
$new_array[$title] = array();
}
}
and the output:
Array
(
[fey palin] => Array
(
)
[big theory] => Array
(
[bang theory] => bang theory
[bang big] => bang big
)
[nyc through] => Array
(
)
[bang theory] => Array << To remove
(
[bang big] => bang big
)
[jonas storm] => Array
(
[storm test] => storm test
)
[bang big] => Array
(
)
[storm test] => Array << To remove
(
)
[plain sahra] => Array
(
)
[mind woolf] => Array
(
[mind virginia] => mind virginia
)
[mind virginia] => Array
(
)
)
The problem is this line:
$new_array[$i] = $title;
This is setting the initial elements of $new_array to strings, not an array. So when you later do
$new_array[$first_key][] = $title;
it's trying to do array_push on a string.
That line should be:
$new_array[$i] = array($title);
Add this statement before the one that triggers the error:
if (!isset($new_array[$first_key])) $new_array[$first_key] = array();
This way you ensure that $new_array[$first_key] is initialised as an array and you can safely add elements to that array.
But your algorithm will still fail, as you use that same array $new_array in your preg_grep call. That will not work as you want when you have added sub-arrays to $new_array.
You need to two variables: one for doing the preg_grep, which you do not change, and one where you add to in your loop. Currently you are mixing these two...

How to encode an associative array grouping one of its members?

How to encode an associative array grouping one of its members?
$my_array = Array(
// customer 1
[0] => Array
(
[customer_id] => 1
[cutomer_item] => 7
)
[1] => Array
(
[customer_id] => 1
[cutomer_item] => 9
)
// customer 2
[2] => Array
(
[customer_id] => 2
[cutomer_item] => 3
)
[3] => Array
(
[customer_id] => 2
[cutomer_item] => 5
)
);
I wanto to group (csv) customers_items like:
[
// customer 1
{
"customer_id" : "1" // customer id preserved
"cutomer_items" : "7,9" // customer items imploded with a comma
}
,
// customer 2
{
"customer_id" : "2"
"cutomer_items" : "3,5"
}
]
I got confused with so many array functions (http://php.net/manual/en/ref.array.php).
You can use group_concat function in mysql query. if u are fetching the result through mysql
Here is an idea:
Code
<?php
$my_array = array(
array('customer_id' => 1, 'cutomer_item' => 7),
array('customer_id' => 1, 'cutomer_item' => 9),
array('customer_id' => 2, 'cutomer_item' => 3),
array('customer_id' => 2, 'cutomer_item' => 7),
);
sort($my_array);
$customer = '';
$gp_array = array();
$carr = false;
foreach($my_array as $item) {
if ($customer!=$item['customer_id']) {
if ($carr!==false) {
$carr['customer_items'] = implode(',',$carr['customer_items']);
$gp_array[] = $carr;
}
$carr = array('customer_id'=>$item['customer_id'], 'customer_items' => array());
}
$customer = $item['customer_id'];
$carr['customer_items'][] = $item['cutomer_item'];
}
if ($carr!==false) {
$carr['customer_items'] = implode(',',$carr['customer_items']);
$gp_array[] = $carr;
}
$json = json_encode($gp_array);
echo $json
?>
Output
[{"customer_id":1,"customer_items":"7,9"},{"customer_id":2,"customer_items":"3,7"}]

PHP Get most repeated value in Array

I have an array within an array like this:
Array
(
[0] => Array
(
[name] => B
[id] => 924572
)
[1] => Array
(
[name] => A
[id] => 120689
)
[2] => Array
(
[name] => A
[id] => 120689
)
[3] => Array
(
[name] => C
[id] => 919644
)
[4] => Array
(
[name] => A
[id] => 120689
)
[5] => Array
(
[name] => B
[id] => 924572
)
)
How can I get the most repeated value from object named name and id?
I've already tried the code below but I'm getting an error: Warning: array_count_values(): Can only count STRING and INTEGER values!
$count = array_count_values($info);
arsort($count);
$popular = array_keys($count);
echo $popular[0];
Any fix regarding to this problem?
"Serializing way" for searching most repeated couples (name,id):
$out = array();
foreach($arr as $el){
$key = serialize($el);
if (!isset($out[$key]))
$out[$key]=1;
else
$out[$key]++;
}
arsort($out);
foreach($out as $el=>$count){
$item = unserialize($el);
echo "Name = ".$item['name'].' ID = '.$item['id'].' Count = '.$count.'<br/>';
}
Output:
Name = A ID = 120689 Count = 3
Name = B ID = 924572 Count = 2
Name = C ID = 919644 Count = 1
update Without loop
.....
arsort($out);
$most = unserialize(key($out));
$most_count = array_shift($out);
echo $most['name'];
echo $most['id'];
echo $most_count;
Output:
A
120689
3
A more linear solution.
$arr = Array
(
Array
(
"name" => "B",
"id" => 924572
),
Array
(
"name" => "A",
"id" => 120689
),
Array
(
"name" => "A" ,
"id" => 120689
),
Array
(
"name" => "C",
"id" => 919644
),
Array
(
"name" => "A",
"id" => 120689
),
Array
(
"name" => "B",
"id" => 924572
));
$countArr = Array();
for($i = 0; $i < count($arr); $i++)
{
$tmpArr = $arr[$i];
if(array_key_exists($tmpArr["name"],$countArr))
$countArr[$tmpArr["name"]]++;
else
$countArr[$tmpArr["name"]] = 0;
}
arsort($countArr);
var_dump($countArr);
Maybe you can work with this solution:
<?php
$info = array(
array(
"name" => "B",
"id" => 924572
),
array(
"name" => "A",
"id" => 120689
),
array(
"name" => "A",
"id" => 120689
),
array(
"name" => "C",
"id" => 919644
),
array(
"name" => "A",
"id" => 120689
),
array(
"name" => "B",
"id" => 924572
),
);
$result = array();
foreach ($info as $infoKey => $infoValue) {
foreach ($infoValue as $itemKey => $itemValue) {
if ($itemKey != "name") {
continue;
}
if (array_key_exists($itemValue, $result)){
$result[$itemValue]++;
continue;
}
$result[$itemValue] = 1;
}
}
arsort($result);
var_dump($result);
Will result in:
array (size=3)
'A' => int 3
'B' => int 2
'C' => int 1
Based on finding the mode and mapping in PHP. Would this work?
$name_array = array_map(function($x) {return $x["name"];}, $info);
$count = array_count_values($name_array);
$mode = array_keys($count, max($count));
To return an array of "name", "id" pairs use:
$return_value = array_filter($info, function($x) use ($mode) { return (in_array($x["name"], $mode));});
Makes use of array_column (requires PHP 5.5 or shim).
$count_values = array_count_values(array_column($array, 'name'));
$most_frequent_name = array_search(max($count_values), $count_values);
Then if you want all arrays with this name:
$items = array_filter($array, function ($v) use ($most_frequent_name) {
return $v['name'] == $most_frequent_name;
});
If several names may have the same top frequency:
$count_values = array_count_values(array_column($array, 'name'));
$most_frequent_names = array_keys($count_values, max($count_values));
$items = array_filter($array, function ($v) use ($most_frequent_names) {
return in_array($v['name'], $most_frequent_names);
});
Try following code. It will give you count of occurrences of all elements
function array_icount_values($arr,$lower=true) {
$arr2=array();
if(!is_array($arr['0'])){$arr=array($arr);}
foreach($arr as $k=> $v){
foreach($v as $v2){
if($lower==true) {$v2=strtolower($v2);}
if(!isset($arr2[$v2])){
$arr2[$v2]=1;
}else{
$arr2[$v2]++;
}
}
}
return $arr2;
}
$arr = array_icount_values($array);
echo "<pre>";
print_r($arr);

Categories