I've tried this with usort, but I didn't succeed.
I've the following array:
array(
[0] => array(
'date' => '3:6:2012'
),
[1] => array(
'date' => '5:5:2012'
),
[2] => array(
'date' => '20:12:2011'
)
)
The date is in d:m:yyyy format, so no leading zero's.
I want to sort the array to get this:
array(
[0] => array(
'date' => '20:12:2011'
),
[1] => array(
'date' => '5:5:2012'
),
[2] => array(
'date' => '3:6:2012'
)
)
I've tried it this way:
function cmp($a, $b) {
if($a['date'] = $b['date']) {
return 0;
}
$partsa = explode(":", $a['date']);
$partsb = explode(":", $b['date']);
$daya = $partsa[0];
$montha = $partsa[1];
$yeara = $partsa[2];
$dayb = $partsb[0];
$monthb = $partsb[1];
$yearb = $partsb[2];
if($yeara < $yearb) {
return -1;
} elseif($yeara > $yearb) {
return 1;
} elseif($yeara == $yearb) {
if($montha < $monthb) {
return -1;
} elseif($montha > $monthb) {
return 1;
} elseif($montha == $monthb) {
if($daya < $dayb) {
return -1;
} elseif($daya > $dayb) {
return 1;
} elseif($daya == $dayb) {
return 0;
}
}
}
}
but this doesn't give good results with usort...
How to do this?
You can create a temporary array with normalized dates (yyyymmdd), then use array_multisort:
$arr = array(
array(
'date' => '3:6:2012'
),
array(
'date' => '5:5:2012'
),
array(
'date' => '20:12:2011'
),
array(
'foo' => 'no date here'
),
);
foreach($arr as $key=>$row) {
if(isset($row['date'])) {
$date = explode(':',$row['date']);
$date = $date[2] . str_pad($date[1],2,'0',STR_PAD_LEFT) . str_pad($date[0],2,'0',STR_PAD_LEFT);
$sort_arr[$key] = $date;
} else {
$sort_arr[$key] = null;
}
}
array_multisort($sort_arr, SORT_ASC, $arr);
print_r($arr);
PHP offers the function strcmp, that's doing the comparing stuff for us. In order to compare the dates correctly, we create timestamp out of it.
But at first we need to parse the string: exploding by : and finally throwing them to mktime.
function cmp($a, $b) {
$a = explode(':', $a['date']);
$a = mktime(0, 0, 0, intval($a[1]), intval($a[0]), intval($a[2]));
$b = explode(':', $b['date']);
$b = mktime(0, 0, 0, intval($b[1]), intval($b[0]), intval($b[2]));
return strcmp($a, $b);
}
Note: The first three arguments of mktime are hours, minutes and seconds and can be ignored in this scenario.
First, make them dates (normal, php-readable dates):
foreach($array as $innerarray){
foreach($innerarray as $key=>$value){
$date = explode(":", $value);
$date = date($date[2]."/".$date[1]."/".$date[0]);
$array[$innerarray][$key] = $date;
}
}
After this, you can sort them with the following function:
function sort_bydate($a, $b) {
return strnatcmp($a['date'], $b['date']);
}
// sort by date
usort($data, 'sort_bydate');
This should do the trick.
By the way, I would advise to not use arrays in arrays, because it is useless in your case.
Related
I have two array containing some value.
$type = array("first", "second", "third");
$date = array(
0 => "2019-04-30",
1 => "2019-05-01",
2 => "2019-05-02",
3 => "2019-05-03"
);
I need output something like this:
[
type :first,
date: [
"2019-04-30": 1.2,
.....
]
]
But for some reason I am not getting in that format.
This is the code I have tried.
$newArr = array();
foreach($type as $tt) {
$newArr[]['type'] = $tt;
$newDate = array();
foreach ($date as $d) {
$newDate[$d] = 1.2;
}
$newArr[]['date'] = $newDate;
}
Can anybody show what I did mistake.
Thank You.
It just comes down to building the array and then adding it in the right order, this builds all of the data and adds it in one go at the end of the loop...
$newArr = array();
foreach($type as $tt) {
$newDate = array();
foreach ($date as $d) {
$newDate[$d] = 1.2;
}
$newArr[] = [ 'type' => $tt, 'date' => $newDate];
}
You could shorten it to this, but it doesn't really make much difference...
foreach($type as $tt) {
$newArr[] = [ 'type' => $tt, 'date' => array_fill_keys($date, 1.2)];
}
Lets make it more simple
$newArr = array();
$newdates = array();
foreach($dates as $date){
$newdates[$date] = 1.2;
}
foreach($type as $tt) {
$newArry[] = array("type"=>$tt,"date"=>$newdates);
}
You can use array_map and array_fill_keys for the desired result
$type = ["first", "second", "third"];
$date = [
0 => "2019-04-30",
1 => "2019-05-01",
2 => "2019-05-02",
3 => "2019-05-03"
];
$newArr = [];
array_map(function($t, $d) use ($date, &$newArr){
$newArr[] = [
'type' => $t,
'date' => array_fill_keys($date, 1.2)
];
}, $type, $date);
I have a string like this:-
$a = " [abc,hjhd],[ccdc,cdc],[csc,vdfv]";
I want to insert this string into an array.
$marker_tower_line = array(
'type' => 'Feature',
'properties' => array(
'marker-color' => '#f00',
'marker-size' => 'small'
),
'geometry' => array(
'type' => 'LineString',
'coordinates' => array (
$a
)
)
);
The output coming is-
["[abc,hjhd],[ccdc,cdc],[csc,vdfv]"];
But I need-
[[abc,hjhd],[ccdc,cdc],[csc,vdfv]];
The most Simplest answer (one-liner with simple php functions):-
<?php
$a = " [abc,hjhd],[ccdc,cdc],[csc,vdfv]";
$b = array_chunk(explode(",",str_replace(array("[","]"),array("",""),trim($a))),2);
print_r($b);
Output:- https://eval.in/833862
Or a bit more shorten (without trim()):-
<?php
$a = " [abc,hjhd],[ccdc,cdc],[csc,vdfv]";
$b = array_chunk(explode(",",str_replace(array("[","]"," "),array("","",""),$a)),2);
print_r($b);
Output:- https://eval.in/833882
i think you are looking for this,
$somearray=explode(",",$a);
then use $somearray for coordinates. The only catch is that you have to use this idea to implement in your logic.For example if $a is the string that you are making then make it like this,
$a = "[abc,hjhd].,[ccdc,cdc].,[csc,vdfv]";
and then use explode as
$somearray=explode(".,",$a);
hope this helps.
You can use this code. The function make_my_array() will work for any string encoded in your given format.
The make_my_array() function takes your string as parameter and iterates through every character to make your output array. It determines staring of a set by '[' character and determines separate set elements by ',' character and the ']' character determines end of a set.
function make_my_array($sa) {
$s = "";
$ans = array();
for($i=0; $i<strlen($sa); $i++) {
$t = array();
if($sa[$i] == '[') {
for($j=$i+1; $j<strlen($sa); $j++) {
if($sa[$j] == ',') {
$t[] = $s;
$s = "";
}
else if($sa[$j] == ']') {
$t[] = $s;
$s = "";
$i = $j + 1;
$ans[] = $t;
break;
}
else {
$s .= $sa[$j];
}
}
}
}
return $ans;
}
$a = " [abc,hjhd],[ccdc,cdc],[csc,vdfv]";
$marker_tower_line = array(
'type' => 'Feature',
'properties' => array(
'marker-color' => '#f00',
'marker-size' => 'small'
),
'geometry' => array(
'type' => 'LineString',
'coordinates' => make_my_array($a)
)
);
I need elements of array 1 that are not present in array 2 based on the 'value' key only.
Array1
$array1 = array(
array('value' => 113214, 'revision_id' => 2047152),
array('value' => 236462, 'revision_id' => 2045678),
array('value' => 236541, 'revision_id' => 2047155)
);
Array2
$array2 = array(
array('value' => 113214, 'revision_id' => 2047152),
array('value' => 236461, 'revision_id' => 2047153),
array('value' => 236541, 'revision_id' => 2047155)
);
I need the output as below, the difference of arrays should be based on Value
$output = array(
array('value' => 236462, 'revision_id' => 2045678)
);
Just do a nested foreach loop and check the condition hope its helps you :
$arraycheck= array();
foreach($newData as $data1) {
$duplicatecheck = false;
foreach($oldData as $data2) {
if($data1['value'] === $data2['value'] && $data1['revision_id'] === $data2['revision_id']) $duplicatecheck = true;
}
if($duplicatecheck === false) $arraycheck[] = $data1;
}
First, use array_column to get the values of 'value' from array2 into a one-dimensional array:
$a2values = array_column($array2, 'value');
Then use those values to array_filter array1.
$result = array_filter($array1, function($item) use ($a2values) {
// only keep items with values not in array2
return !in_array($item['value'], $a2values);
});
You can use array_udiff which accepts last parameter as callback, and you can define your comparison there easily.
$array1 = [
['value' => '113214', 'revision_id' => '2047152'],
['value' => '236462', 'revision_id' => '2045678'],
['value' => '236541', 'revision_id' => '2047155'],
];
$array2 = [
['value' => '113214', 'revision_id' => '2047152'],
['value' => '236461', 'revision_id' => '2047153'],
['value' => '236541', 'revision_id' => '2047155'],
];
$result = array_udiff ($array1, $array2, function($x, $y) {
return $x['value'] - $y['value'];
});
print_r($result);
taken from: https://gist.github.com/wrey75/c631f6fe9c975354aec7
function my_array_diff($arr1, $arr2) {
$diff = array();
// Check the similarities
foreach( $arr1 as $k1=>$v1 ){
if( isset( $arr2[$k1]) ){
$v2 = $arr2[$k1];
if( is_array($v1) && is_array($v2) ){
// 2 arrays: just go further...
// .. and explain it's an update!
$changes = self::diff($v1, $v2);
if( count($changes) > 0 ){
// If we have no change, simply ignore
$diff[$k1] = array('upd' => $changes);
}
unset($arr2[$k1]); // don't forget
}
else if( $v2 === $v1 ){
// unset the value on the second array
// for the "surplus"
unset( $arr2[$k1] );
}
else {
// Don't mind if arrays or not.
$diff[$k1] = array( 'old' => $v1, 'new'=>$v2 );
unset( $arr2[$k1] );
}
}
else {
// remove information
$diff[$k1] = array( 'old' => $v1 );
}
}
// Now, check for new stuff in $arr2
foreach( $arr2 as $k=>$v ){
// OK, it is quite stupid my friend
$diff[$k] = array( 'new' => $v );
}
return $diff;
}
usage:
$diff = my_array_diff($arr1, $arr2);
var_dump($diff);
This question already has answers here:
Sort array using array_multisort() with dynamic number of arguments/parameters/rules/data
(5 answers)
Closed 2 years ago.
I have the problem with sort direction. I try to sort multi-dimensional array with direction. I can't use array_multisort() directly, because I don't know how many parametrs will be. I use call_user_func_array('array_multisort', $params); And it works, but I can't set sort direction (SORT_ASC,SORT_DESC). How can I set sort direction for call_user_func_array('array_multisort', $params);?
Here is my code, you can try it
function get_fields($data, $order_by) {
$order_row = preg_split("/[\s,]+/", $order_by);
for ($i=0;$i<count($order_row);$i++) {
foreach ($data as $key => $row) {
$tmp[$i][$key] = $row[$order_row[$i]];
}
}
return $tmp;
}
function ordering($data, $order_by) {
$tmp = get_fields($data, $order_by);
$params = array();
foreach($tmp as &$t){
$params[] = &$t;
}
$params[1] = array("SORT_DESC","SORT_DESC","SORT_DESC","SORT_DESC"); // like that no warning but no sorting
$params[] = &$data;
call_user_func_array('array_multisort', $params);
return array_pop($params);
}
$data = array (
array('id' => 1,'name' => 'Barack','city' => 9),
array('id' => 7,'name' => 'boris','city' => 2),
array('id' => 3,'name' => 'coris','city' => 2),
array('id' => 3,'name' => 'coris','city' => 2)
);
$order_by = "city desc, name";
echo "<br>ORDER BY $order_by<br>";
$ordered = ordering($data, $order_by);
echo "<pre>";
var_dump($ordered);
echo "</pre>";
I want to do a sort like MySQL ORDER BY city DESC, name. It's my goal.
To be able to sort an array multiple times and achieve a result like ORDER BY city DESC, name ASC you need a function that does a stable sort.
As far as I know PHP doesn't have one so you have to sort it once with a comparator function like this
$data = array (
array('id' => 3,'name' => 'coris','city' => 2),
array('id' => 1,'name' => 'Barack','city' => 9),
array('id' => 7,'name' => 'boris','city' => 2),
array('id' => 3,'name' => 'coris','city' => 2),
);
$order_by = array(
'city' => array('dir' => SORT_DESC, 'type' => SORT_NUMERIC),
'name' => array('dir' => SORT_ASC, 'type' => SORT_STRING),
);
function compare($row1,$row2) {
/* this function should determine which row is greater based on all of the criteria
and return a negative number when $row1 < $row2
a positive number when $row1 > $row2
0 when $row1 == $row2
*/
global $order_by;
foreach($order_by as $field => $sort) {
if($sort['type'] != SORT_NUMERIC) {
// strings are compared case insensitive and assumed to be in the mb_internal_encoding
$cmp = strcmp(mb_strtolower($row1[$field]), mb_strtolower($row2[$field]));
} else {
$cmp = doubleval($row1[$field]) - doubleval($row2[$field]);
}
if($sort['dir'] != SORT_ASC) $cmp = -$cmp;
if($cmp != 0) return $cmp;
}
return 0;
}
usort($data,'compare');
I had the same problem. It seems that call_user_func_array() can't handle the constants.
I've solved this problem by dynamically building an argument string and evaluating this string:
$args = array($arr1, $arr2);
$order = array(SORT_ASC, SORT_DESC);
$evalstring = '';
foreach($args as $i=>$arg){
if($evalstring == ''){ $evalstring.= ', '; }
$evalstring.= '$arg';
$evalstring.= ', '.$order[$i];
}
eval("array_multisort($evalstring);");
I know eval() is evil and this is not a clean way, but it works ;-)
It is working for me :
$arrayThatNeedToSort = array('data..');
$multiSortprop = array(['data.....']=> SORT_DESC,['data.....'] => SORT_ASC)
$properties = array();
foreach ($multiSortprop as $sortArr => $sortArg) {
array_push($properties,$sortArr);
array_push($properties,$sortArg);
}
array_push($properties,$arrayThatNeedToSort);
array_multisort(...$properties);
var_dump(end($properties));
I wanna know how to sort arrays like this:
$array[] = Array (
'name' => '/home/gtsvetan/public_html/presta/cms.php'
'type' => 'text/x-php'
'size' => 1128
'lastmod' => 1339984800
);
$array[] = Array (
'name' => '/home/gtsvetan/public_html/presta/docs/'
'type' => 'dir'
'size' => 0
'lastmod' => 1329253246
);
I wanna to sort it first by type (folders first and then files) and then alphabetical. But I don't know how to sort it.
Best regards,
George!
you can use usort()
In compare function you do two comparisions on name & type - something like below:
function compare_f($a,$b) {
if($a['type']=='dir'&&$b['type']!='dir') return 1;
if($a['type']!='dir'&&$b['type']=='dir') return -1;
if(substr($a['name'],-1,1)=='/') $a['name']=substr($a['name'],0,-1);
if(substr($b['name'],-1,1)=='/') $b['name']=substr($b['name'],0,-1);
$af_array=explode('/',$a['name']);
$a_name=$af_array[count($af_array)-1];
$bf_array=explode('/',$b['name']);
$b_name=$bf_array[count($bf_array)-1];
if($a_name>$b_name)
return 1;
return -1;
}
usort($array,'compare_f');
You can do something like this..
$dir = array();
$file = array();
$dir = array();
$file = array();
foreach($array as $b=>$v) {
if($v['type'] == "dir") {
$dir[] = $v;
} else {
$file[] = $v;
}
}
$combined = array_merge($dir, $file);
Feel free to adjust it.