I have an array $array
$array =>
(
['name'] => (
"Ronaldo","Ribery","Bale","Messi"
),
['rank'] => (
2,4,1,3
)
)
Now How can i sort the array DESC using rank field along with the name
Expected output ->
$array =>
(
['name'] => (
"Ribery","Messi","Ronaldo","Bale"
),
['rank'] => (
4,3,2,1
)
)
A valid use for oft-misunderstood array_multisort()
<?php
$array = [
'name' => ["Ronaldo","Ribery","Bale","Messi"],
'rank' => [2,4,1,3]
];
array_multisort(
$array['rank'], SORT_DESC, SORT_NUMERIC,
$array['name'], SORT_ASC, SORT_STRING
);
var_dump($array);
array(2) {
'name' =>
array(4) {
[0] =>
string(6) "Ribery"
[1] =>
string(5) "Messi"
[2] =>
string(7) "Ronaldo"
[3] =>
string(4) "Bale"
}
'rank' =>
array(4) {
[0] =>
int(4)
[1] =>
int(3)
[2] =>
int(2)
[3] =>
int(1)
}
}
Check out this php article also if you want your two arrays to have a relation than you could better write it like this:
array(
array(
name => 'Messi',
rank => 4,
),
etc..
);
Why not change your data structure to be able to work with objects?
class Player {
public $name; // would be better as private and add getters
public $rank;
public function __construct($name, $rank) {
$this->name = $name;
$this->rank = $rank;
}
}
Then fill your array (I'm not familiar with soccer):
$players = [ // or array(...) if you are using older PHP
new Player('Foo', 3),
new Player('Bar', 1),
new Player('FooBar', 2)
];
Then you can use the regular sort:
// or a function name, if using older PHP
usort($players, function (Player $a, Player $b) {
if ($a->rank == $b->rank) {
return 0;
}
return ($a->rank < $b->rank) ? -1 : 1;
});
Related
I am trying to loop through several database table structures and determine the common structure (ie what columns are identical). The final structure should only show common columns, so if any table has a unique column, it should not be in the final array.
This is an example of what three table structures may look like.
$arr1 = [
["name"=>"col1", "type"=>"varchar"],
["name"=>"col2", "type"=>"int"]
];
$arr2 = [
["name"=>"col1", "type"=>"varchar"],
["name"=>"col2", "type"=>"int"] ,
["name"=>"col3", "type"=>"date"]
];
$arr3 = [
["name"=>"col1", "type"=>"varchar"],
["name"=>"col3", "type"=>"int"]
];
$arrays = [$arr1, $arr2, $arr3];
Using array_merge, array_diff, array_intersect, or a loop, is it possible to determine which of these columns are common to all tables?
The end value should be
[["name"=>"col1", "type"=>"varchar"]]
You could use array_uintersect, which does the intersection with your own function. But you should keep in mind, that the compare function does not simply returns true or false - instead you have to return -1, 0 or 1.
In PHP7 you could use the spaceship operator <=> for the comparison.
$intersection = array_uintersect($arr1, $arr2, $arr3, function($a, $b) {
$ret = $a['name'] <=> $b['name'];
return $ret ? $ret : $a['type'] <=> $b['type'];
});
print_r($intersection);
If you want to put all arrays inside the intersection, you could do this:
$arrays = [$arr1, $arr2, $arr3];
$arrays[] = function($a, $b) {
$ret = $a['name'] <=> $b['name'];
return $ret ? $ret : $a['type'] <=> $b['type'];
};
$intersection = array_uintersect(...$arrays);
In older versions, you should instead use strcasecmp.
You can use a custom compare method with array_uintersect():
$arr1 = [
["name" => "col1", "type" => "varchar"],
["name" => "col2", "type" => "int"]
];
$arr2 = [
["name" => "col1", "type" => "varchar"],
["name" => "col2", "type" => "int"],
["name" => "col3", "type" => "date"]
];
$arr3 = [
["name" => "col1", "type" => "varchar"],
["name" => "col3", "type" => "int"]
];
$common_columns = array_uintersect($arr1, $arr2, $arr3, 'compareDeepValue');
print_r($common_columns);
function compareDeepValue($val1, $val2)
{
return (strcasecmp(serialize($val1), serialize($val2))) ;
}
Will output:
Array
(
[0] => Array
(
[name] => col1
[type] => varchar
)
)
Note:
#Abracadaver made a good point this method will only work correctly when you have the array conventions in the same order.
Than you can for example use this:
function compareDeepValue($val1, $val2)
{
return ($val1['name'] === $val2['name'] && $val1['type'] === $val2['type']) ? 0 : -1;
}
You can extract the arrays and index by the name key and compute the intersection using the keys:
$result = array_intersect_key(array_column($arr1, null, 'name'),
array_column($arr2, null, 'name'),
array_column($arr3, null, 'name'));
Yields:
Array
(
[col1] => Array
(
[name] => col1
[type] => varchar
)
)
If needed, use array_values to get back to numeric indexes.
Maybe ?
$arrays = [$arr1, $arr2, $arr3];
$arrays_extended = [];
foreach($arrays as $row => $innerArray){
foreach($innerArray as $innerRow => $value){
array_push($arrays_extended, $value);
}
}
var_dump(array_unique($arrays_extended));
Outputs [["name"=>"col1", "type"=>"varchar"]]
Approach:
1.convert elements to strings as follows:
array(2) {
[0] =>
string(32) "{"name":"col1","type":"varchar"}"
[1] =>
string(28) "{"name":"col2","type":"int"}"
}
array(3) {
[0] =>
string(32) "{"name":"col1","type":"varchar"}"
[1] =>
string(28) "{"name":"col2","type":"int"}"
[2] =>
string(29) "{"name":"col3","type":"date"}"
}
array(2) {
[0] =>
string(32) "{"name":"col1","type":"varchar"}"
[1] =>
string(28) "{"name":"col3","type":"int"}"
}
2.Use array intersect to find common elements
3.convert back to arrays.
$arr1 = [
["name"=>"col1", "type"=>"varchar"],
["name"=>"col2", "type"=>"int"]
];
$arr2 = [
["name"=>"col1", "type"=>"varchar"],
["name"=>"col2", "type"=>"int"] ,
["name"=>"col3", "type"=>"date"]
];
$arr3 = [
["name"=>"col1", "type"=>"varchar"],
["name"=>"col3", "type"=>"int"]
];
list($darr1, $darr2, $darr3) = convertArrToStr($arr1, $arr2, $arr3);
/* output:
array(2) {
[0] =>
string(32) "{"name":"col1","type":"varchar"}"
[1] =>
string(28) "{"name":"col2","type":"int"}"
}
array(3) {
[0] =>
string(32) "{"name":"col1","type":"varchar"}"
[1] =>
string(28) "{"name":"col2","type":"int"}"
[2] =>
string(29) "{"name":"col3","type":"date"}"
}
array(2) {
[0] =>
string(32) "{"name":"col1","type":"varchar"}"
[1] =>
string(28) "{"name":"col3","type":"int"}"
}
*/
var_dump(duplicates($darr1, $darr2, $darr3));
/* output:
array(1) {
[0] =>
array(2) {
'name' =>
string(4) "col1"
'type' =>
string(7) "varchar"
}
}
*/
function convertArrToStr() {
$args = func_get_args();
foreach($args as &$arg){
foreach($arg as $k => $arr) {
$arg[$k] = json_encode($arr, true);
}
}
return $args;
}
function duplicates($darr1, $darr2, $darr3) {
$intersects = array_intersect($darr1, $darr2, $darr3);
$r = [];
foreach($intersects as $v) {
$r[] = json_decode($v, true);
}
return $r;
}
Hope this helps you write a more elegant solution.
Please help me on how to count the occurrences of value in this associative array.
<?php
$employees = array(
1 => array(
'name' => 'Jason Alipala',
'employee_id' => 'G1001-05',
'position' => 1
),
2 => array(
'name' => 'Bryann Revina',
'employee_id' => 'G1009-03',
'position' => 2
),
3 => array(
'name' => 'Jeniel Mangahis',
'employee_id' => 'G1009-04',
'position' => 2
),
4 => array(
'name' => 'Arjay Bussala',
'employee_id' => 'G1009-05',
'position' => 3
),
5 => array(
'name' => 'Ronnel Ines',
'employee_id' => 'G1002-06',
'position' => 3
)
);
?>
This is my code from fake_db.php which I include_once in the index.php. I want to count the occurrences of the same value of 'position'.. e.g. 1 = 1, 2 = 2, 3 = 2
in addition, there is another array named $positions...
$positions = array(
1 => 'TL',
2 => 'Programmer',
3 => 'Converter');
this array is where i compare the 'position' from the $employees array.
any help is appreciated, thank you!
Combination of array_count_values & array_column (PHP 5 >= 5.5.0, PHP 7) should work -
$counts = array_count_values(
array_column($employees, 'position')
);
Output
array(3) {
[1]=>
int(1)
[2]=>
int(2)
[3]=>
int(2)
}
Update
$final = array_filter($counts, function($a) {
return $a >= 2;
});
Output
array(2) {
[2]=>
int(2)
[3]=>
int(2)
}
Demo
array_column — Return the values from a single column of array. array_count_values — Counts all the values of an array.
$positions = array_column($employees, 'position');
print_r(array_count_values($positions));
Output
Array
(
[1] => 1
[2] => 2
[3] => 2
)
Nested loop will do the job. Take an array, keep the key as the actual value and the value in the key as COUNTER of that key.
if the key exists in array that means it has the value just increment else assign 1 to initialize the key with value 1.
e.g. 1=>counter of 1 (occurrences)
$arrayCounter=0;
foreach($employees as $value){
foreach($value as $data){
$position = $data['position'];
if(array_key_exists($position,$arrayCounter)){
$arrayCounter[$position] = arrayCounter[$position]++;
}
else{
$arrayCounter[$position] = 1;
}
}
It is pretty simple. The array $employees is the array you have supplied. You can use this code:
$data = array();
foreach($employees as $employee) {
if(isset($data[$employee['position']])) {
$data[$employee['position']]++;
} else {
$data[$employee['position']] = 1;
}
}
echo "<pre>";
print_r($data);
echo "</pre>";
This gives the output:
Array
(
[1] => 1
[2] => 2
[3] => 2
)
You can use array_count_value() pre-define php function to get your aim.
you can see result here
$total = 0;
foreach($employees as $eNum => $value){
if($aEmployees[$eNum]['position'] == $key){
$total++;
}
}
echo $total;
These codes are inside a function that is called on every iteration of a foreach loop(another array named '$positions')..
$key is a variable that contains value from that foreach loop (the '$positions' array).. this is what I've done, and it works for me. But i don't know if this is the proper way?
If I have this array -
$data_item['actor_id'] = $this->input->post('actor_id');
$data_item['item_number'] = $this->input->post('item_number');
Which gives me this array -
Array (
[actor_id] => Array (
[0] => 162652153
[1] => 162652154
)
[item_number] => Array (
[0] => 3
[1] => 6
)
)
I need to get my data into this format -
$data = array(
array(
'actor_id' => '3342' ,
'item_number' => '57567'
),
array(
'actor_id' => '876' ,
'item_number' => '94'
)
);
I have tried various ways of looping through it but I can't seem to get it. Such as two seperate loops like this -
foreach($data_item['actor_id'] as $key => $value){
$thevalue[] = array('actor_id' => $value
);
}
But it is wrong format. Any tips please?
What about:
$d = [
'actor_id' => [
1,
2,
],
'item_number' => [
3,
4,
],
];
$res = [];
foreach ( $d as $key => $data ) {
foreach ( $data as $index => $value ) {
$res [ $index ] [$key] = $value;
}
}
I'll generate:
array(2) {
[0]=>
array(2) {
["actor_id"]=>
int(1)
["item_number"]=>
int(3)
}
[1]=>
array(2) {
["actor_id"]=>
int(2)
["item_number"]=>
int(4)
}
}
HTH
you can make use of the actor_id keys to flatten your data as desired:
$data = array(); // your new array
foreach($data_item['actor_id'] as $key => $value) {
// make sure we have an array for this key and add actor id
if (!isset($data[$key])) $data[$key] = array();
$data[$key]['actor_id'] = $value;
// now check if we have an item number for this key and add it
if (isset($data_item['item_number'][$key]))
$data[$key]['item_number'] = $data_item['item_number'][$key];
}
print_r($data);
The result should print out just as you wanted it. Sorry for not having tested the code my self, just typed it out of my head missing time and interpreter right now :)
I am trying to figure out how I can move an array element to another spot. Is this possible?
Here is my example the var_dump array:
array
'person' =>
array
'first_name' =>
array
'...'
'last_name' =>
array
'...'
'rank' =>
array
'...'
'score' =>
array
'...'
'item' =>
array
'...'
'work' =>
array
'company' =>
array
'...'
'phone' =>
array
'...'
And of course there are values in the '...', but just to simplify it. So I need to move "score" before "rank", so the output will show score first before rank, is that possible?
Now I know the array push/pop/shift/unshift but none of those would help me here I think.
Please note, I have no control of this array...I am receiving it as is...
basically it is coming from a Wordpress plugin and it has a filter for these fields so I am using this to catch it.
add_filters( 'work_rank_fields', 'custom_order');
function custom_order($fields) {
var_dump($fields); //what you see on top
}
Using a sample array like you gave us, you could try something like this.
$sample = array(
'person' => array(
'first_name' => array('first'),
'last_name' => array('last'),
'rank' => array('rank'),
'score' => array('score'),
'item' => array('item')
),
'work' => array(
'company' => array('company'),
'phone' => array('phone')
)
);
function reorder_person( $sample )
{
extract( $sample['person'] );
// the desired order below for the keys
$sample['person'] = compact('first_name','last_name','score','rank','item');
return $sample;
}
$sample = reorder_person( $sample );
Now your var_dump of $sample should display score before rank
array(2) {
'person' =>
array(5) {
'first_name' =>
array(1) {
[0] =>
string(5) "first"
}
'last_name' =>
array(1) {
[0] =>
string(4) "last"
}
'score' =>
array(1) {
[0] =>
string(5) "score"
}
'rank' =>
array(1) {
[0] =>
string(4) "rank"
}
'item' =>
array(1) {
[0] =>
string(4) "item"
}
}
'work' =>
array(2) {
'company' =>
array(1) {
[0] =>
string(7) "company"
}
'phone' =>
array(1) {
[0] =>
string(5) "phone"
}
}
}
A little clumsy but, your wordpress filter custom_order function then might look like:
function custom_order( $fields ) {
$a = array();
foreach( $fields['person'] as $key => $value )
{
if ( $key == 'rank' ) continue; // wait until we get score first
if ( $key == 'score' )
{
$a['score'] = $value; // add score first, then rank
$a['rank'] = $fields['person']['rank'];
continue;
}
$a[$key] = $value;
}
$fields['person'] = $a;
return $fields;
}
I'm not sure which is the order criteria but I guess one of this functions can help you. Take a look particularly to last three. You just have to create the appropriate comparison function
I have an array which looks like this
$dataArray = array (
0 =>
array (
'UserId' => '804023',
'ProjectCode' => 'RA1234',
'Role' => 'PI',
),
1 =>
array (
'UserId' => '804023',
'ProjectCode' => 'RA1234',
'Role' => 'PM',
),
2 =>
array (
'UserId' => '804023',
'ProjectCode' => 'A90123',
'Role' => 'CI',
),
3 =>
array (
'UserId' => '804023',
'ProjectCode' => 'A20022',
'Role' => 'PM',
),
)
I need it to look like this
$expected = array (
804023 =>
array (
'RA1234' =>
array (
0 => 'PI',
1 => 'PM',
),
'A90123' =>
array (
0 => 'PI',
),
'A20022' =>
array (
0 => 'CI',
),
),
)
I think this could be achieved generically using recursion as this is a scenario I am likely to come across many times
I have got this far passing in an array of keys that form the nested array keys i.e.
$keys=array("UserId","projectCode","Role");
but am just not seeing where to go from here any pointers?
public function structureData(array $data, array $keys)
{
//$structuredData = array();
foreach ($data as $key => $value)
{
$keyForData = array_slice($keys,0,1);
$remainingKeys = $keys;
array_shift($remainingKeys);
if (!array_key_exists($value[$keyForData[0]], $structuredData))
{
$count=count($remainingKeys);
$structuredData[$value[$keyForData[0]]] =array();
// this returns as expected array(804023 =>array ()); but subsequent recursive calls with the remaining data fail
}
}
return $structuredData);
}
You don't need recursion, just a loop:
foreach ($dataArray as $da) {
$expected[$da['UserId']][$da['ProjectCode']][] = $da['Role'];
}
var_export($expected);
/* output:
array (
804023 =>
array (
'RA1234' =>
array (
0 => 'PI',
1 => 'PM',
),
'A90123' =>
array (
0 => 'CI',
),
'A20022' =>
array (
0 => 'PM',
),
),
)
*/
A crude but functioning solution.
function structureData($data, $keys){
$out = array();
foreach($data as $row){
$subout = &$out;
foreach(array_slice($keys, 0, -1) as $key){
$value = $row[$key];
$subout = &$subout[$value];
}
$subout[] = $row[$keys[count($keys) - 1]];
}
return $out;
}
print_r(structureData($dataArray, array('UserId', 'ProjectCode', 'Role')));
Recursion? Nah. Try this:
function add_role($dataArray, $userid, $project_code, $role)
{
$dataArray[$userid][$project_code][] = $role;
}
Functional solution:
$t = array_gather_key($dataArray, function ($e) { return $e['UserId']; } );
$t = array_map(
function ($e) {
return array_gather_key($e,
function ($e) { return $e['ProjectCode']; },
function ($e) { return $e['Role']; } );
},
$t
);
With this higher-order function:
function array_gather_key($array, $func, $transf = null) {
$res = array();
foreach ($array as $elem) {
$key = $func($elem);
if (!array_key_exists($key, $res))
$res[$key] = array();
if ($transf === null)
$res[$key][] = $elem;
else
$res[$key][] = $transf($elem);
}
return $res;
}
This gives:
array(1) {
[804023]=>
array(3) {
["RA1234"]=>
array(2) {
[0]=>
string(2) "PI"
[1]=>
string(2) "PM"
}
["A90123"]=>
array(1) {
[0]=>
string(2) "CI"
}
["A20022"]=>
array(1) {
[0]=>
string(2) "PM"
}
}
}