I have two arrays like below;
array1 = {
[0]=> 'A'
[1]=> 'B'
[2]=> 'C'
}
array2 = {
[0]=> 'B'
[1]=> 'C'
[2]=> 'D'
}
I want to compare these two arrays and get the difference.
What I need return is like this;
result = {
[0]=> 'A'
[1]=> 'D'
}
I thought I could use array_diff, but it compares key AND value as a pair. I want to compare ONLY values.
How can I do that?
This should work -
array_diff(array_merge($a, $b), array_intersect($a, $b))
Checking difference between all merged and all common.
Related
I got this array:
$array = array('E1211','E2172','E2181','E233','E241','E286');
And I need to order first by first number-letter, i.e. E1, E2, E3, E4... followed by ordered numbers from lowest to highest.
Desired order would be: E1211, E233, E241, E286, E2172, E2181
If i do sort($array); the order will will be: "E1211", "E2172", "E2181", "E233", "E241" "E286".
If i do natsort($array); it will order by numbers from lowest to higest: "E233", "E241", "E286", "E1211", "E2172", "E2181"
Use usort() with a custom comparison function to split the strings and compare the portions.
<?php
$array = array('E1211','E2172','E2181','E233','E241','E286');
usort($array, function($a, $b){
$pfxA = substr($a,0,2); // Get the first two characters of each string
$pfxB = substr($b,0,2);
if ( $pfxA !== $pfxB) {return $pfxA<=>$pfxB;} // If they're not equal, return the spaceship comparison
return (int)substr($a,2)<=>(int)substr($b,2); // Prefixes are equal. Convert the rest to integers and return the spaceship comparison.
});
var_dump($array);
Output:
array(6) {
[0]=>
string(5) "E1211"
[1]=>
string(4) "E233"
[2]=>
string(4) "E241"
[3]=>
string(4) "E286"
[4]=>
string(5) "E2172"
[5]=>
string(5) "E2181"
}
See https://3v4l.org/5qts5
Actually what you want to do is mixing sorting with your own pattern with natsort(). I doubt if it can be accomplished by some oneliner, however it can be done with simple iteration in separate steps, that code does what I think you want (input data modified for better readibility).
<?php
$array = ['E3123', 'E1211', 'E2181', 'E241', 'E286', 'E2172', 'E233'];
$newArray = [];
$finalArray=[];
// Put it into associative array with required keys (two first chars)
foreach ($array as $item) {
$key = substr($item, 0, 2);
$newArray[$key][] = $item;
}
// sort new array by key (two first chars)
ksort($newArray);
// sort each subarray in natural order and put it to final array
foreach ($newArray as $key => $newItem) {
natsort($newArray[$key]);
$finalArray = array_merge($finalArray, $newArray[$key]);
}
// just check
var_dump($finalArray);
Result:
array (size=7)
0 => string 'E1211' (length=5)
1 => string 'E233' (length=4)
2 => string 'E241' (length=4)
3 => string 'E286' (length=4)
4 => string 'E2172' (length=5)
5 => string 'E2181' (length=5)
6 => string 'E3123' (length=5)
How to sort the following array?
I have an multidimensional array that gets filled with total hours for each brand
$totalHours = array(
'brand' => array(),
'project' => array(),
'hours' => array()
);
The output is something like this (project is not filled):
array(3) {
["brand"]=>
array(3) {
[0]=>
string(4) "Nike"
[1]=>
string(9) "Coke Cola"
[2]=>
string(8) "Converse"
}
["project"]=>
array(3) {
[0]=>
string(6) "Bonobo"
[1]=>
string(4) "LDRU"
[2]=>
string(2) "US"
}
["hours"]=>
array(3) {
[0]=>
int(28)
[1]=>
int(106)
[2]=>
string(1) "2"
}
}
Now I would like to sort the array based on the "hours" field.
I've tried the array_multisort but it seems like I simply don't get how this function works and how to apply it to this array.
I have been able to sort an single array with just one row of values. If I apply that to this problem im sorting only the hours field, leaving the others unsorted and therefore the array is corrupted.
The "project" does actually contains a string. It always does. In this example I didn't filled it.
array_multisort should work:
$totalHours = array(
'brand' => array('Nike', 'Coke Cola', 'Converse'),
'project' => array(),
'hours' => array(28, 106, '2')
);
array_multisort($totalHours['hours'], $totalHours['brand']);
var_dump($totalHours);
That data format is not very convenient because there is no direct association between brands and hours, they even sit in different arrays! Plus, the last hour is a string, not an integer.
We're going to have to create an intermediate array to associate them and sort them. We'll then re-inject everything in the original array.
// Make sure both arrays of brands and hours and the same size
if (count($totalHours['brand']) != count($totalHours['hours'])) {
throw new Exception('Invalid data!');
}
// Make sure every hour record is an integer, not a string
$totalHours['hours'] = array_map('intval', $totalHours['hours']);
// array_combine will sort all arrays based on the sorting of the first one
array_multisort($totalHours['hours'], $totalHours['brand'], $totalHours['project']);
EDIT: Using array_multisort was #delprks 's idea originally. Here I applied it to both brand and project arrays.
You cant do that with a single array_* function!
if (project is not filled) always and the indexes of brand and hours are equal, then you can do:
$forsort = array_combine($totalHours["brands"],$totalHours["hours"]);
asort($forsort,SORT_NUMERIC);
$totalHours["brands"]=array_keys($forsort);
$totalHours["hours"]=array_values($forsort);
But, this is just an answer for you question, not best practise at all.
I already saw a lot of questions that ask about the topic but I am unable to solve my problem.
I am fetching an array with menu id items from database and those items can be sometimes be updated.
The array of ids I receive from db is:
array(3) {
[0]=>
int(1)
[1]=>
int(6)
[2]=>
int(2)
}
And I need id 2 (int) to move into the key position 0 ($sortindex) without breaking the array items order. So the desire result would be:
array(3) {
[0]=>
int(2)
[1]=>
int(1)
[2]=>
int(6)
}
For that I am trying to use usort but without success:
usort($data, function($a, $b) use ($sortindex){
if ($a == $b) {
return 0;
}
if ($a == $sortindex) {
return 1;
}
});
This could happen to any other item id. For example I could order id 1 from 0 key position to 2 and the result would be:
array(3) {
[0]=>
int(6)
[1]=>
int(2)
[2]=>
int(1)
}
$array = [1, 6, 2];
array_unshift($array, array_pop($array));
Or possibly:
$array = [1, 6, 2];
$tmp = array_splice($array, 2, 1);
array_unshift($array, $tmp[0]);
You're not really looking for sorting on values, you just want to swap indices.
If you want to insert the value somewhere other than the front of the array, splice it back in with array_splice.
If you have more keys that you need to change around, then sorting may after all become the simplest solution:
uksort($array, function ($a, $b) {
static $keyOrder = [2 => 0, 0 => 1, 1 => 2];
return $keyOrder[$b] - $keyOrder[$a];
});
Perhaps you are seeking asort function
Look at this code:
$a = array('1'=>'1');
$b = array(''=>'');
var_dump(array_merge($a,$b));
the output seems really strange to me:
array(2) {
[0] =>
string(1) "1"
'' =>
string(0) ""
}
Ok, I've changed $a into this: $a = array('k'=>'v'); and the output became more predictable:
array(2) {
'k' =>
string(1) "v"
'' =>
string(0) ""
}
The question is: why the hell the key of the first element is 0 in the first example?
edit:
var_dump($a);
array(1) {
[1] =>
string(1) "1"
}
Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array.
http://php.net/array_merge
Yes, it's an idiosyncrasy of PHP to treat numeric string values as numeric values in this case. You may want to use $a + $b instead.
I have this kind of array:
$a = array(
'one' => 'one',
'0' => '0',
'two' => 'two',
'three' => 'three',
'four'
);
as you can see it is an associative array BUT not all the keys have the value (take a look at the last).
My question is, how can i loop this kind of array to get key(if exists) and the respective value?
Thank you!
The string 'four' in your example is not a key but a value. The corresponding key will be 1. This happens because PHP converts the string key '0' to numeric key 0 and for the value 'four' it uses the next numeric key which will be 1.
Reference:
A key may be either an integer or a string. If a key is the standard
representation of an integer, it will be interpreted as such (i.e. "8"
will be interpreted as 8, while "08" will be interpreted as "08")
To have a key with no value you can use NULL as the value:
'four' => null
Similarly to have an empty key use null as key:
null => 'four'
And to loop over such an array you can use a foreach loop. To detect if a key/value is null or not you can use the isset function.
With var_dump($a); you see all keys and values:
array(5) {
["one"] => string(3) "one"
[0] => string(1) "0"
["two"] => string(3) "two"
["three"] => string(5) "three"
[1] => string(4) "four"
}
you can use the foreach construction:
foreach($a as $key=>$val){
// $key is a current key
// $val is tha current value associated
}
As described in PHP: Arrays
A key may be either an integer or a string. If a key is the standard representation of an integer, it will be interpreted as such (i.e. "8" will be interpreted as 8, while "08" will be interpreted as "08"). Floats in key are truncated to integer. The indexed and associative array types are the same type in PHP, which can both contain integer and string indices.
So you cannot distinguish key '0' and 0. And your last element is not a key, it is a value with auto incremental integer key 1. You can check with var_dump($a):
array(5) {
["one"]=>
string(3) "one"
[0]=>
string(1) "0"
["two"]=>
string(3) "two"
["three"]=>
string(5) "three"
[1]=>
string(4) "four"
}
If you can ensure all your keys do not start with digit, then you can just iterate the array as usual, and test the key using is_int.