Sort PHP array by date - php

I have a bunch of files that are in an array
im(month)(day)(year)
im01012007
im01022006
im01022012
im01032011
im01042010
im01042012
im01052009
im01052011
im01062012
im01072008
im01072011
etc..
is there a way to sort the array so that it sorted by year then month then day?

You can try use usort
$string = "im01012007.jpg,im01022006.jpg,im01022012.jpg,im01032011.jpg,im01042010.jpg,im01042012.jpg,im01052009.jpg,im01052011.jpg,im01062012.jpg,im01072008.jpg,im01072011.jpg";
$array = explode(",", $string); // rebulding your array ;
var_dump($array);
usort($array, function ($a, $b) {
$a = DateTime::createFromFormat("mdY", substr(pathinfo($a, PATHINFO_FILENAME), 2));
$b = DateTime::createFromFormat("mdY", substr(pathinfo($b, PATHINFO_FILENAME), 2));
return ($a == $b) ? 0 : (($a < $b) ? - 1 : 1);
});
var_dump($array);
Output
Before
array
0 => string 'im01012007.jpg' (length=14)
1 => string 'im01022006.jpg' (length=14)
2 => string 'im01022012.jpg' (length=14)
3 => string 'im01032011.jpg' (length=14)
4 => string 'im01042010.jpg' (length=14)
5 => string 'im01042012.jpg' (length=14)
6 => string 'im01052009.jpg' (length=14)
7 => string 'im01052011.jpg' (length=14)
8 => string 'im01062012.jpg' (length=14)
9 => string 'im01072008.jpg' (length=14)
10 => string 'im01072011.jpg' (length=14)
After
array
0 => string 'im01022006.jpg' (length=14)
1 => string 'im01012007.jpg' (length=14)
2 => string 'im01072008.jpg' (length=14)
3 => string 'im01052009.jpg' (length=14)
4 => string 'im01042010.jpg' (length=14)
5 => string 'im01032011.jpg' (length=14)
6 => string 'im01052011.jpg' (length=14)
7 => string 'im01072011.jpg' (length=14)
8 => string 'im01022012.jpg' (length=14)
9 => string 'im01042012.jpg' (length=14)
10 => string 'im01062012.jpg' (length=14)

Yes there is. Convert it to a sensible format first.
I suggest using PHP's DateTime class and keeping all your dates as DateTime objects while you're in the PHP program.
If you don't want to do that, here's a function to sort them in as-is.
usort($myDates, function($a, $b) {
$aBits = array_chunk($a,2);
$bBits = array_chunk($a,2);
$aDate = $aBits[3].$aBits[4].$aBits[2].$aBits[1];
$bDate = $aBits[3].$aBits[4].$aBits[2].$aBits[1];
return ($aDate < $bDate) ? -1 : 1;
});
Hope that helps.

Use substr() and divide your string into parte (day,month,year). Then You can sort them.

No built in function will do this out of the box, i would use usort like this:
usort($files, function($a, $b) {
return strcmp(preg_replace('/^.*(\d{2})(\d{2})(\d{4})$/', '$3$1$2', $a), preg_replace('/^.*(\d{2})(\d{2})(\d{4})$/', '$3$1$2', $b));
});

This will sort oldest to newest. Use krsort to sort newest to oldest.
$files = array();
if ($handle = opendir('/path/to/files')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
$y = substr($entry, 6, 4);
$m = substr($entry, 2, 2);
$d = substr($entry, 4, 2);
$files[$y . $m . $d] = $entry;
}
}
closedir($handle);
}
ksort($files);
I used these PHP Manual entries to write this solution:
readdir
ksort
substr

Related

PHP asort for sorting array items by values ASC?

It is strange with asort, I want to sort the items in an array by their value,
$items = Array ( "1" => 10 , "11" => 10, "22" => 10 );
// Sort an array and maintain index association.
asort($items);
var_dump($items);
So since all values are the same, then asort shouldn't doing anything (I assume), but the result I get,
array (size=3)
22 => string '10' (length=2)
11 => string '10' (length=2)
1 => string '10' (length=2)
It reverses the order!? Why?
what I want (I think it should be like this),
array (size=3)
1 => string '10' (length=2)
11 => string '10' (length=2)
22 => string '10' (length=2)
Any ideas?
EDIT:
I tried with this below,
// Comparison function
private function cmp($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
...
// Sort an array and maintain index association.
uasort($items, array($this, "cmp"));
But I still get the same 'error' result....
Since the version 4.1.0 PHP sort is not stable due to sorting algorithm, which cannot take into account both value and key. You have to use your own implementation of comparison considering key in case of equal values. For example you can modify original array values into (key, value) pairs, sort array and transform it into single dimensional back.
$items = ["1" => 10, "11" => 10, "22" => 10];
$callback = function ($a, $b) use ($callback) {
$result = $a['value'] - $b['value'];
if ($result == 0) {
$result = $a['key'] - $b['key'];
}
return $result;
};
array_walk($items, function (&$value, $key) {
$value = ["key" => $key, "value" => $value];
});
usort($items, $callback);
$items = array_combine(array_column($items, 'key'), array_column($items, 'value'));
print_r($items);

Create a new string with unique char and sorted with frequency first and then asc alphapetical order

A string is given and have to create a string based in the character occurrence and in case of equal occurrence sort it with alphabetical order.
$inputstring = 'ababbdcbeccc';
$stringCharArray = str_split($inputstring);
for($i = 0; $i < strlen($inputstring); $i++ )
{
$character = $stringCharArray[$i];
array_intersect($stringCharArray,array($character));
$array = array_values(array_intersect($stringCharArray,array($character)));
if(!in_array($character ,$uniqueCharArr))
{
$uniqueCharArr[$i] = $array[0];
$uniqueCharFreqArr[$i]['char'] = $array[0];
$uniqueCharFreqArr[$i]['frequency'] = count($array);
}
}
sort($uniqueCharFreqArr);
var_dump($uniqueCharFreqArr);
VAR_DUMP OF ABOVE CODE
array
0 =>
array
'char' => string 'a' (length=1)
'frequency' => int 2
1 =>
array
'char' => string 'b' (length=1)
'frequency' => int 4
2 =>
array
'char' => string 'c' (length=1)
'frequency' => int 4
3 =>
array
'char' => string 'd' (length=1)
'frequency' => int 1
4 =>
array
'char' => string 'e' (length=1)
'frequency' => int 1
OUTPUT
//PRINT OUTPUT STRING
bcade
Any other optimized method?
$frequencies = array_count_values(str_split($inputstring, 1));
arsort($frequencies);
$outputstring = implode('', array_keys($frequencies));
This doesn't meet the requirement that letters with the same frequency should be in alphabetical order. PHP doesn't have a sorting function that looks at both keys and values.
<?php
ini_set( 'xdebug.var_display_max_depth', 4 );
/* INITIALIZATION OF DATA TYPES AND VARIABLES */
$m = 0;
$string = NULL;
/* INPUT VALUE */
$inputstring = 'ababbdcbeccaabbccffttbasdc';
var_dump($inputstring);
$frequencies = array_count_values(str_split($inputstring));
arsort($frequencies);
$charArrWithDecFreq = array_keys($frequencies);
$arrFreqOccr = array_count_values($frequencies);
foreach($arrFreqOccr as $k=>$v)
{
$a = array();
for($i=0; $i<$v; $i++)
$a[] = $charArrWithDecFreq[$m++];
sort($a);
$string .= implode('',$a);
}
/* OUTPUT DUMP TO SCREEN */
var_dump($string);
?>

Shortest way to sort that array in PHP?

I have this array:
array
0 =>
array
'action_operator' => string 'by_fixed' (length=8)
'action_amount' => string '10.0000' (length=7)
'sort_order' => string '0' (length=1)
1 =>
array
'action_operator' => string 'by_percent' (length=10)
'action_amount' => string '10.0000' (length=7)
'sort_order' => string '1' (length=1)
...
I want to sort that according to the sort_order key starting with the lowest (0 in this case). I know I can iterate and so on, but whats the shortest code to achieve that?
Thanks :)
<?php
usort( $aData, function( $a, $b ) {
return ($a['sort_order'] < $b['sort_order'] ? 1 : -1);
} );
With PHP7 you should be able to use the spaceship operator:
usort( $aData, function( $a, $b ) {
return $a['sort_order'] <=> $b['sort_order'];
} );
A one-liner using usort:
usort($array, function($a, $b) { return $a['sort_order'] - $b['sort_order']; });

'cascading' explode string in php

How to explode this string :
00004.00001.00003.00001.00003
in an array like this :
array (size=3)
0 => string '00004' (length=5)
1 => string '00004.00001' (length=10)
2 => string '00004.00001.00003' (length=15)
3 => string '00004.00001.00003.00001.00003' (length=20)
Thx
$array = explode('.', '00004.00001.00003.00001.00003');
foreach($array as $key => $value) {
if($array[$key - 1]) {
$array[$key] = $array[$key - 1] . '.' . $value;
}
}
Explode it first as you would normally do $arr = explode('.', $str); and then build desired array with two loops.
Another version using array_map() :
$arr = explode('.', '00004.00001.00003.00001.00003');
$arr[] = 'blank';
$array = array_map(function(){
global $arr;
array_pop($arr);
return implode($arr);
}, $arr);

What is the best way to split a string into an array of Unicode characters in PHP?

In PHP, what is the best way to split a string into an array of Unicode characters? If the input is not necessarily UTF-8?
I want to know whether the set of Unicode characters in an input string is a subset of another set of Unicode characters.
Why not run straight for the mb_ family of functions, as the first couple of answers didn't?
You could use the 'u' modifier with PCRE regex ; see Pattern Modifiers (quoting) :
u (PCRE8)
This modifier turns on additional
functionality of PCRE that is
incompatible with Perl. Pattern
strings are treated as UTF-8. This
modifier is available from PHP 4.1.0
or greater on Unix and from PHP 4.2.3
on win32. UTF-8 validity of the
pattern is checked since PHP 4.3.5.
For instance, considering this code :
header('Content-type: text/html; charset=UTF-8'); // So the browser doesn't make our lives harder
$str = "abc 文字化け, efg";
$results = array();
preg_match_all('/./', $str, $results);
var_dump($results[0]);
You'll get an unusable result:
array
0 => string 'a' (length=1)
1 => string 'b' (length=1)
2 => string 'c' (length=1)
3 => string ' ' (length=1)
4 => string '�' (length=1)
5 => string '�' (length=1)
6 => string '�' (length=1)
7 => string '�' (length=1)
8 => string '�' (length=1)
9 => string '�' (length=1)
10 => string '�' (length=1)
11 => string '�' (length=1)
12 => string '�' (length=1)
13 => string '�' (length=1)
14 => string '�' (length=1)
15 => string '�' (length=1)
16 => string ',' (length=1)
17 => string ' ' (length=1)
18 => string 'e' (length=1)
19 => string 'f' (length=1)
20 => string 'g' (length=1)
But, with this code :
header('Content-type: text/html; charset=UTF-8'); // So the browser doesn't make our lives harder
$str = "abc 文字化け, efg";
$results = array();
preg_match_all('/./u', $str, $results);
var_dump($results[0]);
(Notice the 'u' at the end of the regex)
You get what you want :
array
0 => string 'a' (length=1)
1 => string 'b' (length=1)
2 => string 'c' (length=1)
3 => string ' ' (length=1)
4 => string '文' (length=3)
5 => string '字' (length=3)
6 => string '化' (length=3)
7 => string 'け' (length=3)
8 => string ',' (length=1)
9 => string ' ' (length=1)
10 => string 'e' (length=1)
11 => string 'f' (length=1)
12 => string 'g' (length=1)
Hope this helps :-)
Slightly simpler than preg_match_all:
preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY)
This gives you back a 1-dimensional array of characters. No need for a matches object.
Try this:
preg_match_all('/./u', $text, $array);
It's worth mentioning that since PHP 7.4 there's a built-in function, mb_str_split, that does this.
$chars = mb_str_split($str);
Unlike preg_split('//u', $str) this supports encodings other than UTF-8.
If for some reason the regex way isn't enough for you. I once wrote the Zend_Locale_UTF8 which is abandoned but might be helping you if you decide to do it on your own.
In particular have a look at the class Zend_Locale_UTF8_PHP5_String which reads in Unicode strings and to work with them splits them up into single chars(which may consist out of multiple bytes obviously).
EDIT:
I just relaized that ZF's svn-browser is down so I copied the important methods for convenience:
/**
* Returns the UTF-8 code sequence as an array for any given $string.
*
* #access protected
* #param string|integer $string
* #return array
*/
protected function _decode( $string ) {
$string = (string) $string;
$length = strlen($string);
$sequence = array();
for ( $i=0; $i<$length; ) {
$bytes = $this->_characterBytes($string, $i);
$ord = $this->_ord($string, $bytes, $i);
if ( $ord !== false )
$sequence[] = $ord;
if ( $bytes === false )
$i++;
else
$i += $bytes;
}
return $sequence;
}
/**
* Returns the UTF-8 code of a character.
*
* #see http://en.wikipedia.org/wiki/UTF-8#Description
* #access protected
* #param string $string
* #param integer $bytes
* #param integer $position
* #return integer
*/
protected function _ord( &$string, $bytes = null, $pos=0 )
{
if ( is_null($bytes) )
$bytes = $this->_characterBytes($string);
if ( strlen($string) >= $bytes ) {
switch ( $bytes ) {
case 1:
return ord($string[$pos]);
break;
case 2:
return ( (ord($string[$pos]) & 0x1f) << 6 ) +
( (ord($string[$pos+1]) & 0x3f) );
break;
case 3:
return ( (ord($string[$pos]) & 0xf) << 12 ) +
( (ord($string[$pos+1]) & 0x3f) << 6 ) +
( (ord($string[$pos+2]) & 0x3f) );
break;
case 4:
return ( (ord($string[$pos]) & 0x7) << 18 ) +
( (ord($string[$pos+1]) & 0x3f) << 12 ) +
( (ord($string[$pos+1]) & 0x3f) << 6 ) +
( (ord($string[$pos+2]) & 0x3f) );
break;
case 0:
default:
return false;
}
}
return false;
}
/**
* Returns the number of bytes of the $position-th character.
*
* #see http://en.wikipedia.org/wiki/UTF-8#Description
* #access protected
* #param string $string
* #param integer $position
*/
protected function _characterBytes( &$string, $position = 0 ) {
$char = $string[$position];
$charVal = ord($char);
if ( ($charVal & 0x80) === 0 )
return 1;
elseif ( ($charVal & 0xe0) === 0xc0 )
return 2;
elseif ( ($charVal & 0xf0) === 0xe0 )
return 3;
elseif ( ($charVal & 0xf8) === 0xf0)
return 4;
/*
elseif ( ($charVal & 0xfe) === 0xf8 )
return 5;
*/
return false;
}
function str_split_unicode($str, $l = 0) {
if ($l > 0) {
$ret = array();
$len = mb_strlen($str, "UTF-8");
for ($i = 0; $i < $len; $i += $l) {
$ret[] = mb_substr($str, $i, $l, "UTF-8");
}
return $ret;
}
return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
}
var_dump(str_split_unicode("لأآأئؤة"));
output:
array (size=7)
0 => string 'ل' (length=2)
1 => string 'أ' (length=2)
2 => string 'آ' (length=2)
3 => string 'أ' (length=2)
4 => string 'ئ' (length=2)
5 => string 'ؤ' (length=2)
6 => string 'ة' (length=2)
for more information : http://php.net/manual/en/function.str-split.php
I was able to write a solution using mb_*, including a trip to UTF-16 and back in a probably silly attempt to speed up string indexing:
$japanese2 = mb_convert_encoding($japanese, "UTF-16", "UTF-8");
$length = mb_strlen($japanese2, "UTF-16");
for($i=0; $i<$length; $i++) {
$char = mb_substr($japanese2, $i, 1, "UTF-16");
$utf8 = mb_convert_encoding($char, "UTF-8", "UTF-16");
print $utf8 . "\n";
}
I had better luck avoiding mb_internal_encoding and just specifying everything at each mb_* call. I'm sure I'll wind up using the preg solution.
the best way for split with length: I just changed laravel str_limit() function:
public static function split_text($text, $limit = 100, $end = '')
{
$width=mb_strwidth($text, 'UTF-8');
if ($width <= $limit) {
return $text;
}
$res=[];
for($i=0;$i<=$width;$i=$i+$limit){
$res[]=rtrim(mb_strimwidth($text, $i, $limit, '', 'UTF-8')).$end;
}
return $res;
}

Categories