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
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.
$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
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()
);
}
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 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. :)