What does array_diff_uassoc() function do in php? - php

I am new to php and i have read the documentation about array_diff_uassoc() function on php.net, w3schools and on other resources on the internet but failed to get what is the use of this function. According to me it is non sense function because its its documentation is so confusing.
As i know first parameter and second parameters are arrays, but what does third parameter do it takes function and it must return less than , greater than or equal to 0 and this and this. What does this nonsense documentation means ?
Following all the examples generate same result.
Example 1
function test($a,$b){
$a > $b ? 1 : -1;
}
$arrayOne = array(
"one"=>"elementOne",
"two"=>"elementTwo",
"three"=>"elementThree"
);
$arrayTwo = array(
"one"=>"elementOne",
"two"=>"elementTwo",
"three"=>"elementThree"
);
$x = array_diff_uassoc($arrayOne,$arrayTwo,'test');
Output
Array
(
[two] => elementTwo
[three] => elementThree
)
Example 2
function test($a,$b){
$a > $b ? -1 : 1;
}
$arrayOne = array(
"one"=>"elementOne",
"two"=>"elementTwo",
"three"=>"elementThree"
);
$arrayTwo = array(
"one"=>"elementOne",
"two"=>"elementTwo",
"three"=>"elementThree"
);
$x = array_diff_uassoc($arrayOne,$arrayTwo,'test');
Output
Array
(
[two] => elementTwo
[three] => elementThree
)
Example 3
function test($a,$b){
$a < $b ? 0 : 1;
}
$arrayOne = array(
"one"=>"elementOne",
"two"=>"elementTwo",
"three"=>"elementThree"
);
$arrayTwo = array(
"one"=>"elementOne",
"two"=>"elementTwo",
"three"=>"elementThree"
);
$x = array_diff_uassoc($arrayOne,$arrayTwo,'test');
Output
Array
(
[two] => elementTwo
[three] => elementThree
)
Example 4
function test($a,$b){
$a < $b ? 0 : 1;
}
$arrayOne = array(
"one"=>"elementOne",
"two"=>"elementTwo",
"three"=>"elementThree"
);
$arrayTwo = array(
"one"=>"elementOne",
"two"=>"elementTwo",
"three"=>"elementThree"
);
$x = array_diff_uassoc($arrayOne,$arrayTwo,'test');
Output
Array
(
[two] => elementTwo
[three] => elementThree
)
So what does this nonsense function means ? Can anyone tell or may be i am wrong ?

The comparison function allows you to create custom logic to determine whether the two entries are the same or not.
The keys in these two arrays look totally different, because they are in different languages.
$data1 = [
'red' => true,
'yellow' => true,
'green' => true,
'blue' => true,
'black' => true,
];
$data2 = [
'rouge' => true,
'jaune' => true,
'bleu' => true,
'vert' => true,
'blanc' => true,
];
But we can still do a diff against them using a custom comparison function that recognises where the two languages have equivalent values
function colourLanguageTest($a, $b) {
static $comparator = [
'red' => 'rouge',
'yellow' => 'jaune',
'green' => 'vert',
'blue' => 'bleu',
'black' => 'noir',
'white' => 'blanc',
];
if (isset($comparator[$a])) {
return $comparator[$a] != $b;
} elseif(isset($comparator[$b])) {
return $comparator[$b] != $a;
}
return true;
}
$result = array_diff_uassoc($data1, $data2, 'colourLanguageTest');
var_dump($result);
The comparison function checks for the entries in the comparator table, so it can identify that red and rouge are the same, and treat them as a match. A boolean false (0) will be returned if there is a match a boolean true (1) if there is no match.
Because this is a diff function, it filters out all entries from the first array where our custom logic returns 0 (indicating a match) and leaves only entries where our comparison logic doesn't return a 0 (ie returns 1 or -1 or 999 or -23456)
Because 'red', 'yellow', 'green' and 'blue' all have corresponding entries in the second array that match according to the language lookup, only 'black' doesn't have a corresponding entry in the second data array, so the result of our call to array_diff_uassoc() returns
array(1) {
["black"]=>
bool(true)
}

there must be a return value in your callback "test" function
function test($a,$b){
if ($a === $b) {
return 0;
}
return ($a > $b)? 1:-1;
}
$arrayOne = array(
"one"=>"elementOne",
"two"=>"elementTwo",
"three"=>"elementThree"
);
$arrayTwo = array(
"one"=>"elementOne",
"two"=>"elementTwo",
"three"=>"elementThree"
);

Related

Compare 2 similar arrays and remove all similar items in the beginning

I have 2 similar arrays:
$array_a = array(
array(
"id" => 1,
"merchant_reference" => "12345"
),
array(
"id" => 2,
"merchant_reference" => "67890"
)
);
$array_b = array(
array(
"id" => 1,
"merchant_reference" => "12345"
),
array(
"id" => 2,
"merchant_reference" => "67890"
),
array(
"id" => 3,
"merchant_reference" => "12345"
)
);
The only difference is $array_b has an additional item. I'd like to output a new array that counts the total keys of $array_a and removes all keys in $array_b up to that count. And, just leave the 3rd item in $array_b.
I've tried:
function compare_arrays($array1, $array2) {
$array1_count = count($array1);
$array2_count = count($array2);
$array2_count = $array2_count - $array1_count;
$array2 = array_slice($array2, $array1_count, $array2_count);
return $array2;
}
But, what's the best way to do this?
As per the discussion under comment, your code is fine, just an additional conditional check which will improve execution time in case no addition after 12 pm is found.
function compare_arrays($array1, $array2) {
$array1_count = count($array1);
$array2_count = count($array2);
$array2_count = $array2_count - $array1_count;
if($array2_count > 0){
return $array2 = array_slice($array2, $array1_count, $array2_count);
}
return $array1;
}

How to check if a single multi dimensional array contails same array as value in php? [duplicate]

I'd like to check if two arrays are equal. I mean: same size, same index, same values. How can I do that?
Using !== as suggested by a user, I expect that the following would print enter if at least one element in the array(s) are different, but in fact it does not.
if (($_POST['atlOriginal'] !== $oldAtlPosition)
or ($_POST['atl'] !== $aext)
or ($_POST['sidesOriginal'] !== $oldSidePosition)
or ($_POST['sidesOriginal'] !== $sideext)) {
echo "enter";
}
$arraysAreEqual = ($a == $b); // TRUE if $a and $b have the same key/value pairs.
$arraysAreEqual = ($a === $b); // TRUE if $a and $b have the same key/value pairs in the same order and of the same types.
See Array Operators.
EDIT
The inequality operator is != while the non-identity operator is !== to match the equality
operator == and the identity operator ===.
According to this page.
NOTE: The accepted answer works for associative arrays, but it will not work as expected with indexed arrays (explained below). If you want to compare either of them, then use this solution. Also, this function may not works with multidimensional arrays (due to the nature of array_diff function).
Testing two indexed arrays, which elements are in different order, using $a == $b or $a === $b fails, for example:
<?php
(array("x","y") == array("y","x")) === false;
?>
That is because the above means:
array(0 => "x", 1 => "y") vs. array(0 => "y", 1 => "x").
To solve that issue, use:
<?php
function array_equal($a, $b) {
return (
is_array($a)
&& is_array($b)
&& count($a) == count($b)
&& array_diff($a, $b) === array_diff($b, $a)
);
}
?>
Comparing array sizes was added (suggested by super_ton) as it may improve speed.
Try serialize. This will check nested subarrays as well.
$foo =serialize($array_foo);
$bar =serialize($array_bar);
if ($foo == $bar) echo "Foo and bar are equal";
Short solution that works even with arrays which keys are given in different order:
public static function arrays_are_equal($array1, $array2)
{
array_multisort($array1);
array_multisort($array2);
return ( serialize($array1) === serialize($array2) );
}
function compareIsEqualArray(array $array1,array $array2):bool
{
return (array_diff($array1,$array2)==[] && array_diff($array2,$array1)==[]);
}
Compare them as other values:
if($array_a == $array_b) {
//they are the same
}
You can read about all array operators here:
http://php.net/manual/en/language.operators.array.php
Note for example that === also checks that the types and order of the elements in the arrays are the same.
if (array_diff($a,$b) == array_diff($b,$a)) {
// Equals
}
if (array_diff($a,$b) != array_diff($b,$a)) {
// Not Equals
}
From my pov it's better to use array_diff than array_intersect because with checks of this nature the differences returned commonly are less than the similarities, this way the bool conversion is less memory hungry.
Edit Note that this solution is for plain arrays and complements the == and === one posted above that is only valid for dictionaries.
Another method for checking equality regardless of value order works by using http://php.net/manual/en/function.array-intersect.php, like so:
$array1 = array(2,5,3);
$array2 = array(5,2,3);
if($array1 === array_intersect($array1, $array2) && $array2 === array_intersect($array2, $array1)) {
echo 'Equal';
} else {
echo 'Not equal';
}
Here's a version that works also with multidimensional arrays using http://php.net/manual/en/function.array-uintersect.php:
$array1 = array(
array(5, 2),
array(3, 6),
array(2, 9, 4)
);
$array2 = array(
array(3, 6),
array(2, 9, 4),
array(5, 2)
);
if($array1 === array_uintersect($array1, $array2, 'compare') && $array2 === array_uintersect($array2, $array1, 'compare')) {
echo 'Equal';
} else {
echo 'Not equal';
}
function compare($v1, $v2) {
if ($v1===$v2) {
return 0;
}
if ($v1 > $v2) return 1;
return -1;
}
One way: (implementing 'considered equal' for https://www.rfc-editor.org/rfc/rfc6902#section-4.6)
This way allows associative arrays whose members are ordered differently - e.g. they'd be considered equal in every language but php :)
// recursive ksort
function rksort($a) {
if (!is_array($a)) {
return $a;
}
foreach (array_keys($a) as $key) {
$a[$key] = ksort($a[$key]);
}
// SORT_STRING seems required, as otherwise
// numeric indices (e.g. "0") aren't sorted.
ksort($a, SORT_STRING);
return $a;
}
// Per https://www.rfc-editor.org/rfc/rfc6902#section-4.6
function considered_equal($a1, $a2) {
return json_encode(rksort($a1)) === json_encode(rksort($a2));
}
Syntax problem on your arrays
$array1 = array(
'a' => 'value1',
'b' => 'value2',
'c' => 'value3',
);
$array2 = array(
'a' => 'value1',
'b' => 'value2',
'c' => 'value3',
);
$diff = array_diff($array1, $array2);
var_dump($diff);
Here is the example how to compare to arrays and get what is different between them.
$array1 = ['1' => 'XXX', 'second' => [
'a' => ['test' => '2'],
'b' => 'test'
], 'b' => ['no test']];
$array2 = [
'1' => 'XX',
'second' => [
'a' => ['test' => '5', 'z' => 5],
'b' => 'test'
],
'test'
];
function compareArrayValues($arrayOne, $arrayTwo, &$diff = [], $reversed = false)
{
foreach ($arrayOne as $key => $val) {
if (!isset($arrayTwo[$key])) {
$diff[$key] = 'MISSING IN ' . ($reversed ? 'FIRST' : 'SECOND');
} else if (is_array($val) && (json_encode($arrayOne[$key]) !== json_encode($arrayTwo[$key]))) {
compareArrayValues($arrayOne[$key], $arrayTwo[$key], $diff[$key], $reversed);
} else if ($arrayOne[$key] !== $arrayTwo[$key]) {
$diff[$key] = 'DIFFERENT';
}
}
}
$diff = [];
$diffSecond = [];
compareArrayValues($array1, $array2, $diff);
compareArrayValues($array2, $array1, $diffSecond, true);
print_r($diff);
print_r($diffSecond);
print_r(array_merge($diff, $diffSecond));
Result:
Array
(
[0] => DIFFERENT
[second] => Array
(
[a] => Array
(
[test] => DIFFERENT
[z] => MISSING IN FIRST
)
)
[b] => MISSING IN SECOND
[1] => DIFFERENT
[2] => MISSING IN FIRST
)
array_diff — Computes the difference of arrays
http://php.net/manual/en/function.array-diff.php
array array_diff ( array $array1 , array $array2 [, array $... ] )
Compares array1 against one or more other arrays and returns the values in array1 that are not present in any of the other arrays.
If you want to check non associative arrays, here is the solution:
$a = ['blog', 'company'];
$b = ['company', 'blog'];
(count(array_unique(array_merge($a, $b))) === count($a)) ? 'Equals' : 'Not Equals';
// Equals
The following solution works with custom equality functions that you can pass as a callback. Note that it doesn't check arrays order.
trait AssertTrait
{
/**
* Determine if two arrays have the same elements, possibly in different orders. Elements comparison function must be passed as argument.
*
* #param array<mixed> $expected
* #param array<mixed> $actual
*
* #throws InvalidArgumentException
*/
public static function assertArraysContainSameElements(array $expected, array $actual, callable $comparisonFunction): void
{
Assert::assertEquals(\count($expected), \count($actual));
self::assertEveryElementOfArrayIsInAnotherArrayTheSameAmountOfTimes($expected, $actual, $comparisonFunction);
self::assertEveryElementOfArrayIsInAnotherArrayTheSameAmountOfTimes($actual, $expected, $comparisonFunction);
}
/**
* #param array<mixed> $needles
* #param array<mixed> $haystack
*
* #throws InvalidArgumentException
*/
private static function assertEveryElementOfArrayIsInAnotherArrayTheSameAmountOfTimes(
array $needles,
array $haystack,
callable $comparisonFunction
): void {
Assert::assertLessThanOrEqual(\count($needles), \count($haystack));
foreach ($needles as $expectedElement) {
$matchesOfExpectedElementInExpected = \array_filter(
$needles,
static fn($element): bool => $comparisonFunction($expectedElement, $element),
);
$matchesOfExpectedElementInActual = \array_filter(
$haystack,
static fn($element): bool => $comparisonFunction($expectedElement, $element),
);
Assert::assertEquals(\count($matchesOfExpectedElementInExpected), \count($matchesOfExpectedElementInActual));
}
}
}
I usually use it in database integrations tests when I want to ensure that the expected elements are returned but I don't care about the sorting.
The proper way to compare whether two arrays are equal is to use strict equality (===), which compares recursively. Existing answers are unable to recursively sort an arbitrary array (array of arbitrary depth and order, containing a mixture of sequential and associative arrays) and hence cannot handle comparisons of arbitrary arrays. Sequential arrays are associative arrays with a sequential key (0,1,2,3...) whereas associative arrays do not have a sequential key.
To sort these arbitrary arrays, we have to:
Traverse downwards towards leaf nodes with no more sub-arrays
Sort sequential arrays by serializing then sorting them (to remove the need of having to use custom comparators)
Sort associative arrays by key
The following code implements the solution described above. Improvements to the code are welcome.
function recur_sort( &$array ) {
foreach ( $array as &$value ) {
if ( is_array( $value ) ) recur_sort( $value );
}
if ( is_sequential_array( $array ) ) {
$array = array_map( function( $el ) { return json_encode( $el ); }, $array );
sort( $array, SORT_STRING );
$array = array_map( function( $el ) { return json_decode( $el, true ); }, $array );
return;
} else {
return ksort( $array );
}
}
function is_sequential_array(Array &$a) {
$n = count($a);
for($i=0; $i<$n; $i++) {
if(!array_key_exists($i, $a)) {
return false;
}
}
return true;
}
Example (in PHPUnit):
//A stricter and recursive assertEqualsCanonicalizing
public function assertSameCanonicalizing( $expected, $actual ) {
recur_sort( $expected );
recur_sort( $actual );
$this->assertSame( $expected, $actual );
}
If you want to check that your arrays have the strictly equal (===) associations of keys and values, you can use the following function:
function array_eq($a, $b) {
// If the objects are not arrays or differ in their size, they cannot be equal
if (!is_array($a) || !is_array($b) || count($a) !== count($b)) {
return false;
}
// If the arrays of keys are not strictly equal (after sorting),
// the original arrays are not strictly equal either
$a_keys = array_keys($a);
$b_keys = array_keys($b);
array_multisort($a_keys);
array_multisort($b_keys);
if ($a_keys !== $b_keys) {
return false;
}
// Comparing values
foreach ($a_keys as $key) {
$a_value = $a[$key];
$b_value = $b[$key];
// Either the objects are strictly equal or they are arrays
// which are equal according to our definition. Otherwise they
// are different.
if ($a_value !== $b_value && !array_eq($a_value, $b_value)) {
return false;
}
}
return true;
}
To compare the values of your arrays, also multidimensional, associative and in any combination:
/**
* #see PHPUnit Assert::assertEqualsCanonicalizing()
* #return true if all keys and values are equal and of the same type,
* irregardless of items or keys order
*/
function array_vals_equal(array $a, array $b): bool {
// sort multi-dimensional recursive
$_deep_sort = function (array $a) use (&$_deep_sort): array{
// sort discarding index association or sort keys, depending on array type
array_is_list($a) ? sort($a) : ksort($a);
return array_map(fn($v) => is_array($v) ? $_deep_sort($v) : $v, $a);
};
// operator === checks that the count, types and order of the elements are the same
return $_deep_sort($a) === $_deep_sort($b);
}
// Test cases
assertEquals(array_vals_equal([1], [1]), true, 'simple eq');
assertEquals(array_vals_equal([0], [false]), false, 'simple eq');
assertEquals(array_vals_equal([0], [null]), false, 'simple eq');
assertEquals(array_vals_equal([0, 1], [1, 0]), true, 'simple eq, diff order');
assertEquals(array_vals_equal([0, 1, 2], [1, 0]), false, 'diff count');
assertEquals(array_vals_equal([0, 1], [0, 1, 2]), false, 'diff count 2');
assertEquals(array_vals_equal([1, 2], [1, 2, 'hello']), false, 'diff count 3');
//
assertEquals(array_vals_equal([1, 2, 2], [2, 1, 1]), false, 'same vals repeated');
assertEquals(array_vals_equal([1, 2, 2], [2, 2, 1]), true, 'same vals, different order');
//
assertEquals(array_vals_equal([1, 2, 3], ['1', '2', '3']), false, 'int should not be eq string');
assertEquals(array_vals_equal([0 => 'a', 1 => 'b'], [0 => 'b', 1 => 'a']), true, 'same vals, diff order');
assertEquals(array_vals_equal(['a', 'b'], [3 => 'b', 5 => 'a']), true, 'same vals, diff indexes');
// associative arrays whose members are ordered differently
assertEquals(array_vals_equal(['aa' => 'a', 'bb' => 'b'], ['bb' => 'b', 'aa' => 'a']), true, 'dict with different order');
assertEquals(array_vals_equal(['aa' => 'a', 'bb' => 'b'], ['aa' => 'a']), false, 'a key is missing');
assertEquals(array_vals_equal(['aa' => 'a', 'bb' => 'b'], ['aa' => 'a', 'zz' => 'b']), false, 'dict same vals diff key');
// nested arrays with keys in different order
assertEquals(array_vals_equal(
['aa' => 'a', 'bb' => ['bb' => 'b', 'aa' => 'a']],
['aa' => 'a', 'bb' => ['aa' => 'a', 'bb' => 'b']]
), true, 'dict multi 2 level, keys in different order');
assertEquals(array_vals_equal(
['aa' => 'a', 'bb' => ['aa2' => 'a', 'bb2' => ['aa3' => 'a', 'bb3' => 'b']]],
['aa' => 'a', 'bb' => ['aa2' => 'a', 'bb2' => ['aa3' => 'a', 'bb3' => 'b']]]
), true, 'dict multi 3 level');
assertEquals(array_vals_equal(
['aa' => 'a', 'bb' => [0, 1]],
['aa' => 'a', 'bb' => [1, 0]]
), true, 'dict multi level, 2^ level sequential in different order');
assertEquals(array_vals_equal([[0, 1], ['a', 'b']], [['b', 'a'], [1, 0]]), true, 'multi level sequential');
If you'd like to generate a detailed report, you could use something like this:
function deepCompare(Array $a, Array $b, string $parentAKey, string $parentBKey, bool $compareInverted = true, bool $compareValues = true, string $log = '')
{
foreach ($a as $aKey => $aValue) {
$fullAKey = implode('.', [$parentAKey, $aKey]);
$fullBKey = implode('.', [$parentBKey, $aKey]);
if (! isset($b[$aKey])) {
$log .= "⍰ {$fullAKey} has no equivalent {$fullBKey}\n";
} else {
$bValue = $b[$aKey];
if (is_array($aValue)) {
$log = deepCompare($aValue, $bValue, $fullAKey, $fullBKey, false, $compareValues, $log);
} else {
if ($compareValues) {
if ($aValue != $bValue) {
$log .= "≠ {$fullAKey} value differs from {$fullBKey}\n";
}
}
}
}
}
if ($compareInverted) {
$log = deepCompare($b, $a, $parentBKey, $parentAKey, false, false, $log);
}
return $log;
}
Here is an example for it:
$november = [
'site1' => [
'id' => 15,
'name' => 'Brazil',
'extendedHours' => 454,
],
'site2' => [
'id' => 43,
'name' => 'Portugal',
'extendedHours' => 448,
],
'site3' => [
'id' => 49,
'name' => 'Spain',
'extendedHours' => 0,
],
'totalExtendedHours' => 902,
];
$december = [
'site1' => [
'id' => 15,
'name' => 'Brazil',
'extendedHours' => 498,
],
'site2' => [
'id' => 43,
'name' => 'Portugal',
'extendedHours' => 409,
'extraRequests' => 6,
],
'totalExtendedHours' => 907,
'totalExtraRequests' => 6,
];
echo deepCompare(
$november, -- origin array
$december, -- target array
'Nov2022', -- descriptive name of origin array
'Dec2022', -- descriptive name of target array
true, -- should also compare arrays in reverse order?
true -- should care about array values? (false = names only)
);
This example will output:
≠ Nov2022.site1.extendedHours value differs from Dec2022.site1.extendedHours
≠ Nov2022.site2.extendedHours value differs from Dec2022.site2.extendedHours
⍰ Nov2022.site3 has no equivalent Dec2022.site3
≠ Nov2022.totalExtendedHours value differs from Dec2022.totalExtendedHours
⍰ Dec2022.site2.extraRequests has no equivalent Nov2022.site2.extraRequests
⍰ Dec2022.totalExtraRequests has no equivalent Nov2022.totalExtraRequests
I hope that helps someone.
Use php function array_diff(array1, array2);
It will return a the difference between arrays. If its empty then they're equal.
example:
$array1 = array(
'a' => 'value1',
'b' => 'value2',
'c' => 'value3'
);
$array2 = array(
'a' => 'value1',
'b' => 'value2',
'c' => 'value4'
);
$diff = array_diff(array1, array2);
var_dump($diff);
//it will print array = (0 => ['c'] => 'value4' )
Example 2:
$array1 = array(
'a' => 'value1',
'b' => 'value2',
'c' => 'value3',
);
$array2 = array(
'a' => 'value1',
'b' => 'value2',
'c' => 'value3',
);
$diff = array_diff(array1, array2);
var_dump($diff);
//it will print empty;

Sort MultiDimensional Array by Number Value with Zero Last

What I'm trying to do is sort a multidimensional array by a number but have any values equal to 0, to be at the end of the array.
This code works for sorting with 0's and single digits, but it seems to break when different numbers are added to it.
The output needs to be:
41,42,43,44,45,46,0,0,0
<?php
$array = array(
array(
"position" => 41,
),
array(
"position" => 43,
),
array(
"position" => 42,
),
array(
"position" => 44,
),
array(
"position" => 45,
),
array(
"position" => 0,
),
array(
"position" => 0,
),
array(
"position" => 0,
),
array(
"position" => 46,
),
);
// Sort ascending
usort($array, 'sortByPosition');
// Show result
echo '<pre>';
print_r($array);
function sortByPosition($a, $b) {
return $a['position'] != 0 ? $a['position'] - $b['position'] : $b['position'] - $a['position'];
}
Your comparison function is a bit off. I would do it like this:
function sortByPosition($a, $b) {
if ($a['position'] == $b['position']) return 0;
if ($a['position'] == 0) return 1;
if ($b['position'] == 0) return -1;
return $a['position'] > $b['position'] ? 1 : -1;
}
First, if both positions are the same, return 0, regardless of
whether either of them are zero.
Second and third, if either of them are zero, that one should sort
after the other (since it already would have returned if they were
both zero).
Fourth, neither are zero, so just compare the values normally.
This way:
usort($array, function ($a, $b) {
if (!$a['position']) return 1;
if (!$b['position']) return -1;
return $a['position']-$b['position'];
});

PHP sorting array based on keys in the order as alphabet then numberic and then special chars

I have an array like below,
array(
[!] = array(),
[a] = array(),
[.] = array(),
[n] = array(),
[3] = array(),
[1] = array());
I need to sort this array as,
array(
[a] = array(),
[n] = array(),
[1] = array(),
[3] = array(),
[!] = array(),
[.] = array());
How to do this in php()?
TL;TR
The shortest way (both in terms of code and, after some basic comparisons) is the code I suggest near the "Demo2" link below:
uksort($arr, function($a, $b)
{
if (ctype_alnum("$a") === ctype_alnum("$b"))
return $a > $b;
return "$a" < "$b";
});
You can sort an array using the keys with the ksort function:
ksort($array, SORT_STRING);
The second argument is telling PHP to compare all the keys (including the numeric indexes) as strings (meaning an index like 3 will be treated as if it were '3'). This will give you an array where the keys are in ascending order. The order of the keys you show (all single characters) will be the same as their respective ASCII values (. is 46, a is 97 and so on). Seeing as you want to reverse the order, you'll have to use the array_reverse function:
$array = array_reverse($array, true);
Again, the second argument is telling PHP to preserve the keys, if not, the indexes will be reset, leaving you with a numerically indexed array.
You can skip the array_reverse call quite easily by using the uksortfunction. It works much the same way as ksort, but takes a callback function as a second argument, so you can sort by index, in descending order, too:
uksort($arr, function($a, $b)
{
return "$a" < "$b";//added quotes to convert to strings
});
Demo
You will note that this places the '.' key in front of the '!' key. In fact, if both keys are of the same type (numeric, alpha), it would appear you want to sort them in ascending order, which you can do easily:
uksort($arr, function($a, $b)
{
if (ctype_alnum("$a") === ctype_alnum("$b"))//both are alnums, sort ascending
return $a > $b;//sort ascending
return "$a" < "$b";//else sort descending
});
Demo2
If your PHP version doesn't support anonymous functions, you can define a function and pass its name as second argument, but really: you ought to upgrade:
function sortDesc($a, $b)
{
if (ctype_alnum("$a") === ctype_alnum("$b"))
return $a > $b;
return (string) $a < "$b";//casting is valid, too... both do the same thing
}
uksort($array, 'sortDesc');
// function to sort the array keys with
function compare($a, $b)
{
// Look for [A-z]
if (ctype_alpha($a)) {
if (ctype_alpha($b)) {
return strcasecmp($a, $b);
} else {
return -1;
}
} elseif (ctype_alpha($b)) {
return 1;
}
if (is_int($a)) {
if (is_int($b)) {
return $a > $b;
} else {
return -1;
}
} elseif (is_int($b)) {
return 1;
}
return $a > $b;
}
$a = array(
'!' => array(),
'a' => array(),
'.' => array(),
'n' => array(),
'3' => array(),
'1' => array()
);
// use the function we defined above to sort the array.
uksort($a, "compare");
You can try:
<?php
$arr = array(
'!' => array(),
'a' => array(),
'.' => array(),
'n' => array(),
'3' => array(),
'1' => array(),
'$' => array(),
'8' => array(),
'm' => array(),
'x' => array(),
'c' => array(),
);
function mySort($arr){
$keys = array_keys($arr);
sort($keys);
$result = array();
$temp = array();
foreach($keys as $key){
if(!is_numeric($key) && !ctype_alpha($key)){
$temp[$key] = $arr[$key];
}else{
$result[$key] = $arr[$key];
}
}
foreach($temp as $k => $v){
$result[$k] = $v;
}
return $result;
}
print_r(mySort($arr));
?>
Result:
Array
(
[a] => Array()
[c] => Array()
[m] => Array()
[n] => Array()
[x] => Array()
[1] => Array()
[3] => Array()
[8] => Array()
[!] => Array()
[$] => Array()
[.] => Array()
)

Is there a cleaner way to filter by key's value?

$a = array(
0 => array( 'one' => 1, 'two' => 2 ),
1 => array( 'one' => 3, 'two' => 4 ),
2 => array( 'one' => 5, 'two' => 2 )
);
$c = count( $a );
$r = array();
for ( $i = 0; $i < $c; $i++ )
{
if ( $a[$i]['two'] == 2 )
$r[] = $a[$i];
}
Is there a cleaner way then to do all of the above?
Have you tried using array_filter()?
$r = array_filter($a, function($var) {
return ($var['two'] === 2);
});
The output of the above is slightly different than your original code:
Yours:
array(
0 => array('one' => 1, 'two' => 2),
1 => array('one' => 5, 'two' => 2)
)
Using array_filter:
array(
0 => array('one' => 1, 'two' => 2),
2 => array('one' => 5, 'two' => 2) // Note the key is 2, not 1
)
If you need the keys collapsed, you can follow up the array_filter() with array_values() or array_multisort()
You could write a function to do just this and then use array_walk or array_filter but that's about it.
Only way I can see to clean it up more would be to change the original datastructure.

Categories