sort multi dimension array based on date - php

i have dates and names in text form in file like
2-4-2020,bat
14-3-2020,ball
25-6-2019,purse
27-8-2019,rice
so i m trying to sort it in ascending order
<?php
$newdates=$mydates=array();
$lines = file('n:/mydata.txt');
foreach($lines as $data)
{
$mydates[]=explode(',',$data);
}
$countdates=count($mydates);
for ($i=0;$i<$countdates;$i++){
$chkdate=$mydates[$i][0];
$currentdate=DateTime::createFromFormat('d-m-Y', $chkdate)->format('d-m-Y');
$mydates[$i][0]=$currentdate;
}
array_multisort($mydates);
$newdates=$mydates;
$file = fopen("n:/newdates.txt","w");
foreach ($newdates as $contentline)
{
fputcsv($file,$contentline);
}
fclose($file);
but its not sorting at all

It might be done a little simpler. You need to use usort() and strtotime() functions.
Here is simplified example
$mydates= array(
['2-4-2020','bat'],
['14-3-2020','ball'],
['25-6-2019','purse'],
['27-8-2019','rice']
);
usort($mydates, function($a,$b) {
return strtotime($a[0]) > strtotime($b[0]);
});
foreach ($mydates as $contentline) {
echo json_encode($contentline);
}

You can read the file into an array using the file function. Then you can sort the array using usort:
$fileName = 'n:/mydata.txt';
$lines = file($fileName);
usort($lines, function($a, $b) {
foreach (['a', 'b'] as $variable) {
$parts = explode(',', $$variable);
$$variable = DateTime::createFromFormat('j-n-Y', $parts[0]);
}
return $a < $b ? -1 : 1;
});
file_put_contents(implode("\n", $lines), $fileName);

Related

PHP array with url values to new array with combined values

I have tried for a long time but couldn't find a way to merge an array in to a new one.
Mostly I get lost in looping and matching.;(
I would like to recieve a php 5 method that can do the following:
Example 1
Lets say there is an array with url's like:
Array(
'a',
'a/b/c',
'a/b/c/d/e',
'a/y',
'b/z',
'b/z/q/',
)
Every last folder of the url's is the folder where a user has the right to view.
I would like to send the array to a method that returns a new array like:
Array[](
'a/c/e'
'a/y'
'z/q'
)
The method has combined some elements of the origninal array into one element.
This because there is a match in allowed ending folders.
Example 2
Array(
'projects/projectA/books'
'projects/projectA/books/cooking/book1'
'projects/projectA/walls/wall'
'projects/projectX/walls/wall'
'projects/projectZ/'
'projects/projectZ/Wood/Cheese/Bacon'
)
I would like to get a an array like:
Array[](
'books/book1'
'wall'
'wall'
'projectZ/Bacon'
)
Then it would be great (specialy in case of the 'wall' values) to have some references to the full path's of the original array.
Do it like below:-
<?php
$array = Array(
'projects/projectA/books',
'projects/projectA/books/cooking/book1',
'projects/projectA/walls/wall',
'projects/projectX/walls/wall',
'projects/projectZ/',
'projects/projectZ/Wood/Cheese/Bacon'
);// original array
$final_array =array(); // new array variable
foreach($array as $key=>$arr){ // iterate over original array
$exploded_string = end(array_filter(explode('/',$arr))); // get last-value from the url string
foreach($array as $ar){ // iterate again the original array to compare this string withh each array element
$new_exploded_string = end(array_filter(explode('/',$ar))); // get the new-last-values from url string again
if($arr !== $ar && strpos($ar,$exploded_string) !==false){ // if both old and new url strings are not equal and old-last-value find into url string
if($exploded_string == $new_exploded_string ){ // if both new-last-value and old-last-value are equal
$final_array[] = $exploded_string;
}else{
$final_array[] = $exploded_string.'/'.$new_exploded_string ;
}
}
}
}
print_r($final_array);
Output:-https://eval.in/846738
Well, there isn't a single built-in function for this ;)
$items = array(
'projects/projectA/books',
'projects/projectA/books/cooking/book1',
'projects/projectA/walls/wall',
'projects/projectX/walls/wall',
'projects/projectZ/',
'projects/projectZ/Wood/Cheese/Bacon',
'hold/mold/gold/sold/fold',
'hold/mold/gold',
'raja/maza/saza',
'raja/maza',
'mohit/yenky/client/project',
);
echo '$items = ' . nl2br(htmlspecialchars(print_r($items, true))); //Debug
// Sort, so the shorter basePath comes before the longer subPath
usort($items, function($a, $b) {
if (strlen($a) == strlen($b)) {
return 0;
} else {
return strlen($a) > strlen($b) ? 1 : -1;
}
});
$result = array();
while($basePath = array_shift($items)) { // As long as there is a next item
$basePath = rtrim($basePath, '/'); // Right trim extra /
foreach($items as $idx => $subPath) {
if (strpos($subPath, $basePath . '/') === 0) {
// $subPath begins with $basePath
$result[] = preg_replace('#.*/#', '', $basePath) . '/' . preg_replace('#.*/#', '', rtrim($subPath, '/'));
unset($items[$idx]); // Remove item from array, so it won't be matched again
continue 2; // Continue with next while($basePath = array_shift($items))
}
}
// No subPath found, otherwise continue would have called (skipping below code)
$result[] = preg_replace('#.*/#', '', $basePath);
}
echo '$result = ' . nl2br(htmlspecialchars(print_r($result, true))); //Debug
PHPFiddle: http://phpfiddle.org/main/code/ugq9-hy0i
You can avoid using nested loops (and, actually, you should avoid):
sort($array);
$carry = array_shift($array);
$result = [];
$i = 0;
$lastItem = array_reduce($array, function ($carry, $item) use (&$result, &$i) {
$result[$i] = isset($result[$i])
? array_merge($result[$i], [basename($carry)])
: [basename($carry)];
if (strpos($item, $carry) !== 0) {
$i += 1;
}
return $item;
}, $carry);
if (!empty($lastItem)) {
$result[$i] = isset($result[$i])
? array_merge($result[$i], [basename($lastItem)])
: [basename($lastItem)];
}
$result = array_map(function ($item) {
return implode('/', $item);
}, $result);
Here is working demo.
We use array_reduce here to get access to the previously processed item. Also, PHP has function basename, that retrieves the basename. So you can use it and do not reinvent the wheel.

Search in Multidimensional Array in PHP

$data = array
(
array("Ravi","Kuwait",350),
array("Sameer","UK",400),
array("Aditi","Switzerland",50),
array("Akshay","India",250),
array("rishi","Singapore",200),
array("Mukul","Ireland",100)
);
I want to put condition to the third row such that I can get entries of less than 300.
I suppose that you meant "the third element" in each nested array.Use array_filter function to get an array of elements, those third element's value is less than 300:
$result = array_filter($data, function($v) { return $v[2] < 300; });
print_r($result);
Try this code:
<?php
$data = array
(
array("Ravi","Kuwait",350),
array("Sameer","UK",400),
array("Aditi","Switzerland",50),
array("Akshay","India",250),
array("rishi","Singapore",200),
array("Mukul","Ireland",100)
);
$newArray = array();
foreach($data as $key => $value)
{
if($value[2] <= 100)
$newArray[] = $value;
}
print_r($newArray);
?>
You can achieve this using the PHP function array_filter() :
PHP
function limitArray($array) {
return ($array[2] <= 300);
}
print_r(array_filter($data, 'limitArray'));
evalIN

Creating new multidimensional array from existing fours one dimensional arrays in PHP

I have an arrays like:
$array1=array(1,2,3,4),
$array2=array("test1","test2","test3","test4"),
$array3=array("2014","2015","2014","2015"),
$array4=array("201","101","203","104")
Now I want to create a new multidimensional array $array4 with values like:
[0]=>{"1","test1","2014","201"}
[1]=>{"2","test2","2015","101"}
[2]=>{"3","test3","2014","203"}
[3]=>{"4","test4","2015","104"}
The code you need is given as an example in the documentation page of function array_map():
$output = array_map(NULL, $array1, $array2, $array3, $array4);
That's all!
try this function:
$array1=array(1,2,3,4);
$array2=array("test1","test2","test3","test4");
$array3=array("2014","2015","2014","2015");
$array4=array("201","101","203","104");
print_r(convert($array1, $array2, $array3, $array4));
function convert() {
$newArr = [];
$arrays = func_get_args();
for ($i = 0; $i < count($arrays);$i++) {
for ($k = 0; $k < count($arrays[$i]); $k++) {
$newArr[$k][$i] = $arrays[$i][$k];
}
}
return $newArr;
}
You can make use of array_map to achieve the desired result:
$merge = function() {
return func_get_args();
};
$result = array_map($merge, $array1, $array2, $array3, $array4);
var_dump($result)
It looks like a job for function array_column():
// Combine all the input arrays into a single 2-dimensional array
// Pass the combined array to a function that will return the list
// of its columns
$output = transpose(array($array1, $array2, $array3, $array4));
function transpose(array $array)
{
// Store the result here
$result = array();
// Get each column, put it into the result
foreach (array_keys($array[0]) as $key) {
$result[$key] = array_column($array, $key);
}
return $result;
}
Another solution that works the same but uses function array_reduce() to walk the array:
function transpose(array $array)
{
return array_reduce(
array_keys($array[0]),
function (array $carry, $key) use ($array) {
$carry[$key] = array_column($array, $key);
return $carry;
},
array()
);
}

How to set variables in an array PHP

I am trying to read in a text file which has 21 names like this;
123, bill, bobs
124, joe, public
I have been able to put them into an array but I don't know how to set each name as a variable, as I need to sort them into alphabetical order based on their last name. This is my code so far;
$file = fopen("students.txt", "r");
If ($file) {
while (!feof($file)) {
$array = explode("/n", fread($file, filesize("students.txt")));
print_r($array);
}
} else {
echo 'File unopened';
}
I have tried the following code but it doesnt seem to work;
fscanf ($fp, "%s, %s, %s/n", $num, $first, $last). "<br/>";
Just read the entire file into an array, and explode each line, then usort the results.
$array = file('your_file.txt');
if(false === $array) {
// you had a problem reading file
exit();
}
$exploded_array = array();
foreach($array as $csv) {
$exploded_array[] = explode(',', $csv)
}
usort($exploded_array, function ($a, $b) {
if ($a[2] == $b[2]) {
return 0;
}
return ($a[2] < $b[2]) ? -1 : 1;
}
You can also look at using fgetscv() instead of the combination of file() and explode(). Either way it is pretty much the same.
Your file related code is overcomplicated.
$users = file('students.txt', FILE_SKIP_EMPTY_LINES);
array_walk($users, function (&$val) {
$newAr = explode(',', $val);
$val = array_map('trim', $newAr);
});
usort($users, function($a, $b) {
return strnatcmp($a[2], $b[2]);
});
var_dump($users);
Example with fake data #3v4l
Alternativly you may use fgetcsv to get the values from the file as #MarkB pointed out in the comments of your question

can i glob dirnames to an array and then usort by a file value?

Can anyone please advise whether I can write a function for usort that will do the following in PHP :
Firstly I have a bunch of directories that all have two files inside - these two files each contain a number as plain text
Here is what I want to do :
glob the list of directories into an array call $dirs
use a usort function to do the following :
Read the two files (file1.txt and file2.txt) in each directory and multiply them together to create a 3rd number called $value
Sort the original $dirs array into descending order by the $value for each dir.
Ok - I can glob the files like this:
$dirs = glob('*',GLOB_NOSORT|GLOB_ONLYDIR);
and I can pull the values easily enough using file_get_contents but I can't figure out how to combine all of this into a function for usort.
Try this:
<?php
$dirs = array();
foreach (glob('*',GLOB_NOSORT|GLOB_ONLYDIR) as $dir) {
$value =
(int)file_get_contents($dir.'/file1.txt') *
(int)file_get_contents($dir.'/file2.txt') ;
$dirs[] = array(
'path' => $dir,
'value' => $value,
);
}
usort($dirs, function($a, $b) {
return $b['value'] - $a['value'];
});
Then you want to get one-dimensional result,
$dirs = array_map(function ($dir) {
return $dir['path'];
}, $dirs);
The following snippet will do the trick:
$dirs = glob('*',GLOB_NOSORT|GLOB_ONLYDIR);
usort($dirs, function ($a, $b) {
$val_a = $val_b = 1;
foreach(scandir($a) as $file) {
if(strpos($file, '.') === 0) {
continue;
}
$val_a *= intval(trim(file_get_contents($a. '/' . $file)));
}
foreach(scandir($b) as $file) {
if(strpos($file, '.') === 0) {
continue;
}
$val_b *= intval(trim(file_get_contents($b. '/' . $file)));
}
if($val_a === $val_b) {
return 0;
} else if($val_a > $val_b) {
return 1;
} else {
return -1;
}
});
var_dump($dirs);
Assuming you're using 5.3.0 or better, you can use an anonymous function to do this. Below you will see the function buildSort, which returns a function object (called by PHP a "closure", although it's heavily debated in some circles whether this term is being correctly applied.) We'll use this to "memoize" the reads of dir/file1.txt and dir/file2.txt, as well as the math operations, so we only need to perform those once per directory:
<?php
function buildSort(&$values) {
return function ($a, $b) use(&$values) {
if (!isset($values[$a])) {
$values[$a] = file_get_contents($a.'/file1.txt')*
file_get_contents($a.'/file2.txt');
}
if (!isset($values[$b])) {
$values[$b] = file_get_contents($b.'/file1.txt')*
file_get_contents($b.'/file2.txt');
}
return strcmp($values[$a], $values[$b]);
};
}
$dirs = glob('*',GLOB_NOSORT|GLOB_ONLYDIR);
$values = array();
$sort = buildSort($values);
usort($dirs, $sort);
var_dump($dirs);
The answer that avoids passing $values by reference is left as an exercise for the reader. :)

Categories