I'm trying to compare two array with array_udiff, but it's very weired. it seems array_udiff not get the right answer. Here is the live demo. The result should be an empty array, but leave one element unfiltered out.
<?php
$string = '{
"sakiniai": [
{
"Faktas": "A",
"value": "true"
},
{
"Faktas": "B",
"value": "true"
},
{
"Faktas": "A",
"value": "false"
}
]
}';
$sakiniais = json_decode($string, true)['sakiniai'];
$v = $sakiniais[0];
$arr[] = $v;
$v['value'] = $v['value'] == "true" ? "false" : "true";
$arr[] = $v;
var_dump($arr);
var_dump($sakiniais);
print_r(array_udiff($arr, $sakiniais, function($a, $b){
/*
var_dump($a);
var_dump($b);
var_dump($a == $b);
echo "\n\n\n";
*/
return $a == $b ? 0 : -1;}
));
the output
array(2) {
[0]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
[1]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(5) "false"
}
}
array(3) {
[0]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
[1]=>
array(2) {
["Faktas"]=>
string(1) "B"
["value"]=>
string(4) "true"
}
[2]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(5) "false"
}
}
Array
(
[1] => Array
(
[Faktas] => A
[value] => false
)
)
The problem is that array_udiff is not performing the comparison between all values, and this seems to be caused by your compare function.
array_udiff() expects that the callable function is a real compare function, but you are returning always 0 and -1, but never 1.
Before doing its job, array_udiff() tries to order both arrays and remove duplicates too. If it can't rely on your comparison function, it can't perform all the needed comparison and some values are "jumped".
Look at all comments in the documentation expecially napcoder comment
Note that the compare function is used also internally, to order the
arrays and choose which element compare against in the next round.
If your compare function is not really comparing (ie. returns 0 if
elements are equals, 1 otherwise), you will receive an unexpected
result.
This is demonstrated looking at your arrays
$arr
array(2) {
[0]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
[1]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(5) "false"
}
}
and $sakiniais
array(3) {
[0]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
[1]=>
array(2) {
["Faktas"]=>
string(1) "B"
["value"]=>
string(4) "true"
}
[2]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(5) "false"
}
}
You should expect all the combinations between the two arrays to be tested, but the tested combinations (below) doesn't include A-False vs. A-False
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(5) "false"
}
bool(false)
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
array(2) {
["Faktas"]=>
string(1) "B"
["value"]=>
string(4) "true"
}
bool(false)
array(2) {
["Faktas"]=>
string(1) "B"
["value"]=>
string(4) "true"
}
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(5) "false"
}
bool(false)
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
bool(true)
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(5) "false"
}
bool(false)
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(5) "false"
}
array(2) {
["Faktas"]=>
string(1) "B"
["value"]=>
string(4) "true"
}
bool(false)
In the correct answer at this post there are some other useful insights on how array_udiff works
You can change your return statement like this
if ($a < $b) {
return -1;
} elseif ($a > $b) {
return 1;
} else {
return 0;
}
(if you are wondering how two arrays can be compared for less/greater, have a look at this link, in the section "Comparison with Various Types" and the "Example #2 Transcription of standard array comparison" example)
Nothing strange, everything works as expected. Take a look at arrays comparing:
$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.
so, $arr[0] == $sakiniai[0] is true, but $arr[1] == $sakiniai[2] is false and the output is $arr[1]
$arr
array(2) {
[0]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
[1]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(5) "false"
}
}
$sakiniai
array(3) {
[0]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(4) "true"
}
[1]=>
array(2) {
["Faktas"]=>
string(1) "B"
["value"]=>
string(4) "true"
}
[2]=>
array(2) {
["Faktas"]=>
string(1) "A"
["value"]=>
string(5) "false"
}
}
result
Array
(
[1] => Array
(
[Faktas] => A
[value] => false
)
)
Related
I'm working on algorithm to display my events on the website.
I want to sort my multidimensional array by specific key value.
My array:
["2022-02-28"]=>
array(1) {
[0]=>
array(3) {
["post_id"]=>
string(4) "3656"
["time"]=>
string(5) "16:05"
["priority"]=>
string(1) "0"
}
}
["2022-03-01"]=>
array(2) {
[2]=>
array(3) {
["post_id"]=>
string(4) "3656"
["time"]=>
string(5) "16:05"
["priority"]=>
string(1) "0"
}
[3]=>
array(3) {
["post_id"]=>
string(4) "3784"
["time"]=>
string(5) "13:00"
["priority"]=>
string(1) "0"
}
}
["2022-03-03"]=>
array(1) {
[5]=>
array(3) {
["post_id"]=>
string(4) "3663"
["time"]=>
string(5) "13:06"
["priority"]=>
string(1) "1"
}
}
}
I want to sort the array by "time" key value. So for example at this index :
["2022-03-01"]=>
array(2) {
[2]=>
array(3) {
["post_id"]=>
string(4) "3656"
["time"]=>
string(5) "16:05"
["priority"]=>
string(1) "0"
}
[3]=>
array(3) {
["post_id"]=>
string(4) "3784"
["time"]=>
string(5) "13:00"
["priority"]=>
string(1) "0"
}
}
I want first 13:00 to appear then 16:05. Thank you for your help in advance! :)
Try with this:
<?php
$arr = array();
$arr["2022-02-28"] = [
array("post_id"=>"3656", "time"=>"16:05", "priority"=>"0"),
array("post_id"=>"4856", "time"=>"13:05", "priority"=>"3")];
$arr["2022-03-01"] = [
array("post_id"=>"3656", "time"=>"16:05", "priority"=>"0"),
array("post_id"=>"3636", "time"=>"13:05", "priority"=>"1")
];
foreach($arr as $key => $value){
usort($value, function($a,$b){
return strtotime($a["time"])>strtotime($b["time"]);
});
$arr[$key] = $value;
}
echo "<pre>";
var_dump($arr);
echo "</pre>";
Output:
array(2) {
["2022-02-28"]=>
array(2) {
[0]=>
array(3) {
["post_id"]=>
string(4) "4856"
["time"]=>
string(5) "13:05"
["priority"]=>
string(1) "3"
}
[1]=>
array(3) {
["post_id"]=>
string(4) "3656"
["time"]=>
string(5) "16:05"
["priority"]=>
string(1) "0"
}
}
["2022-03-01"]=>
array(2) {
[0]=>
array(3) {
["post_id"]=>
string(4) "3636"
["time"]=>
string(5) "13:05"
["priority"]=>
string(1) "1"
}
[1]=>
array(3) {
["post_id"]=>
string(4) "3656"
["time"]=>
string(5) "16:05"
["priority"]=>
string(1) "0"
}
}
Use usort for define custom sort.
function time_sort(array $arr){
usort($arr, function($a, $b){
return strcmp($a['time'], $b['time']);
});
}
I'm having trouble looping through an object array and displaying data from it under certain conditions.
I want the webpage to display the following:
<p>John Doe</p> <p>William Green</p> <p>Jane Smith</p>
I know how to do this by defining $user[0]->first_name . $user[0]->last_name specifically, but what I need is a way for the code to loop through and display the names dynamically using the user_id property as a unique identifier.
For all objects in the array with user_id 1, return "these values." For all the objects in the array with user_id 2, return "these values." And so on...looping through each unique user_id.
Here is a var_dump of the object array:
array(4)
{ [0]=> object(stdClass)#4336 (4)
{
["umeta_id"]=> string(1) "1"
["user_id"]=> string(1) "1"
["meta_key"]=> string(10) "first_name"
["meta_value"]=> string(4) "John"
}
[1]=> object(stdClass)#4333 (4)
{
["umeta_id"]=> string(1) "2"
["user_id"]=> string(1) "1"
["meta_key"]=> string(9) "last_name"
["meta_value"]=> string(3) "Doe"
}
[2]=> object(stdClass)#4334 (4)
{
["umeta_id"]=> string(1) "3"
["user_id"]=> string(1) "2"
["meta_key"]=> string(10) "first_name"
["meta_value"]=> string(4) "Jane"
}
[3]=> object(stdClass)#4334 (4)
{
["umeta_id"]=> string(1) "4"
["user_id"]=> string(1) "2"
["meta_key"]=> string(9) "last_name"
["meta_value"]=> string(5) "Smith"
}
[4]=> object(stdClass)#4334 (4)
{
["umeta_id"]=> string(1) "5"
["user_id"]=> string(1) "3"
["meta_key"]=> string(10) "first_name"
["meta_value"]=> string(7) "William"
}
[5]=> object(stdClass)#4334 (4)
{
["umeta_id"]=> string(1) "6"
["user_id"]=> string(1) "3"
["meta_key"]=> string(9) "last_name"
["meta_value"]=> string(5) "Green"
}
}
When I output the information on the webpage, I want it to look like this:
<p>John Doe</p> <p>William Green</p> <p>Jane Smith</p>
Maybe I need to loop through objects and build new arrays based on user_ids? Please do not provide code with echo or print_r. Only "return" can be used for this project.
So $your_object is already sorted by umeta_id and user_id fields?
If not, you can use usort:
function cmp1($a, $b)
{
return strcmp($a->umeta_id, $b->umeta_id);
}
function cmp2($a, $b)
{
return strcmp($a->user_id, $b->user_id);
}
usort($your_object, "cmp1");
usort($your_object, "cmp2");
Then simply:
$str = '';
for($i=0;$i<count($your_object);$i+=2){
$str .= "<p>".$your_object[$i]->meta_value." "$your_object[$i+1]->meta_value."</p> ";
}
return $str; // this var contain all your data in string
Hope this helps!
This will generate the first-name and last-name pairs :
$user_group = array();
ksort($user_group, SORT_NUMERIC);
foreach ($users as $key => $item) {
$name_meta = get_object_vars($item);
foreach ($name_meta as $meta_in => $names) {
if ($names == 'first_name') {
$user_group[$item->user_id]['first_name'] = $name_meta['meta_value'];
}
if ($names == 'last_name') {
$user_group[$item->user_id]['last_name'] = $name_meta['meta_value'];
}
}
}
Output :
array(3) {
[1]=>
array(2) {
["first_name"]=>
string(4) "John"
["last_name"]=>
string(3) "Doe"
}
[2]=>
array(2) {
["first_name"]=>
string(4) "Jane"
["last_name"]=>
string(5) "Smith"
}
[3]=>
array(2) {
["first_name"]=>
string(7) "William"
["last_name"]=>
string(5) "Green"
}
}
And to print the user name pairs :
foreach ($user_group as $name) {
echo "<p>" . $name['first_name'] . " " . $name['last_name'] . "</p>";
}
How can I fetch the value "3" from this set of arrays:
array(1) { [0]=> string(1) "1" }
array(1) { [0]=> string(1) "3" }
array(1) { [0]=> string(1) "0" }
The arrays are output from a foreach statement of parenting array, which is:
array(3) { [0]=> string(8) "St" [1]=> string(1) "1" [2]=> string(1) "0" }
array(3) { [0]=> string(16) "Fu" [1]=> string(1) "3" [2]=> string(1) "0" }
array(3) { [0]=> string(13) "Pa" [1]=> string(1) "0" [2]=> string(1) "0" }
Where I am going for the second line value: "Fu" [1]=> string(1) "3"
Maybe I am doing it wrong from the first array?
You're not giving us much to go on. Are the 3 arrays already in a parent array, in an object, etc.? Below is how to get the # 3 from the 3 arrays...but I'm guessing this is not actually what you are asking, we likely need much more detail...the real problem you are trying to solve.
function getThree($arr1, $arr2, $arr3) {
$array = array();
$array[] = $arr1;
$array[] = $arr2;
$array[] = $arr3;
foreach( $array AS $subArray ) {
// whichever condition works for you
if( $subArray[0] == 'Fu' || $subArray[1] == 3 ) {
return $subArray;
}
}
}
Here is the start of my array:
array(19) {
[0]=> array(3) {
["id"]=> string(2) "46"
["title"]=> string(7) "A"
["thumb"]=> string(68) "013de1e6ab2bfb5bf9fa7de648028a4aefea0ade816b935dd423ed1ce15818ba.jpg"
}
[1]=> array(3) {
["id"]=> string(2) "47"
["title"]=> string(7) "B"
["thumb"]=> string(68) "9df2be62d615f8a6ae9b7de36671c9907e4dadd3d9c3c5db1e21ac815cf098e6.jpg"
}
[2]=> array(3) {
["id"]=> string(2) "49"
["title"]=> string(6) "Look 7"
["thumb"]=> string(68) "0bfb2a6dd1142699ac113e4184364bdf5229517d98d0a428b62f6a72c8288dac.jpg"
}
}
How can I use array_search on this? I need to get the id of an element.
with use of === operator compared types have to be exactly same, in this code you have to search string or just use == instead ===.
function searchId($id, $array) {
foreach ($array as $key => $val) {
if ($val['id'] === $id) {
return $key;
}
}
return null;
}
$id = searchId('46', $yourarray);
Given arrays 'a1' and 'b1' how may they be combined them to produce the final array? Basically replacing the value within 'a1' with the array data for the matching value within 'b1'. I guess the question would be if there is a function that can do this that I'm not seeing.
$a1 = array('id1'=>array('a'=>'444-444',
'b'=>'222-222',
'c'=>'111-111'),
'id2'=>array('a'=>'888-888',
'b'=>'666-666',
'c'=>'555-555')
);
$b1 = array('222-222'=>array('first'=>array('9999',
'dddd',
'yyyy'),
'second'=>'mmgghh'
),
'666-666'=>array('first'=>array('bbbb',
'cccc',
'7777'),
'second'=>'ffffgggg'
)
);
Desired combination:
array(2) {
["id1"]=>
array(3) {
["a"]=>
string(7) "444-444"
["b"]=>
array(1) {
["222-222"]=>
array(2) {
["first"]=>
array(3) {
[0]=>
string(4) "9999"
[1]=>
string(4) "dddd"
[2]=>
string(4) "yyyy"
}
["second"]=>
string(6) "mmgghh"
}
}
["c"]=>
string(7) "111-111"
}
["id2"]=>
array(3) {
["a"]=>
string(7) "888-888"
["b"]=>
array(1) {
["666-666"]=>
array(2) {
["first"]=>
array(3) {
[0]=>
string(4) "bbbb"
[1]=>
string(4) "cccc"
[2]=>
string(4) "7777"
}
["second"]=>
string(6) "ffffgggg"
}
}
["c"]=>
string(7) "555-555"
}
}
array_walk_recursive($a1,function(&$value,$key,$addin){
if(is_scalar($value) && isset($addin[$value])){
$value = array($value=>$addin[$value]);
}
},$b1);