PHP - Create unlimited depth array [duplicate] - php

This question already has answers here:
PHP, regex and multi-level dashes and grouping together according to string occurrence
(2 answers)
Closed 4 years ago.
I have to build sitemap.html generator, that creates a tree of URLs.
So for instance if I have those URLs:
https://some.url/with/something/good/ and https://some.url/with/something/bad/
it will create something like this:
- https://some.url/
- https://some.url/with/
- https://some.url/with/something/
- https://some.url/with/something/good/
- https://some.url/with/something/bad/
I have array of every URL from my site, now I was thinking of building multidimensional array.
Example above would be converted to something like this:
$url_structure['https://some.url/']['https://some.url/with/']['https://some.url/with/something/']['https://some.url/with/something/good/'] = 0;
Which will look like this:
Array
(
[https://some.url/] => Array
(
[https://some.url/with/] => Array
(
[https://some.url/with/something/] => Array
(
[https://some.url/with/something/good/] => 0
[https://some.url/with/something/bad/] => 0
)
)
)
)
Have you got an idea how to do that better? That's the only solution I have in mind so far.
Problem is I can't find the way to create something like this, because I don't really know how depth this array will become. I just have array of URLs (around 20k URLs).
Output to sitemap.html is a list that I did above.

You can use a reference variable to do the job in such way
$list = [
'https://some.url/with/something/good/',
'https://some.url/with/something/bad/',
];
$res = [];
foreach ($list as $x) {
// remove root. you can add it after loop.
$x = substr($x, strlen('https://some.url/'));
$path = preg_split('~/+~', trim($x, '/'));
// point to the array
$p = &$res;
foreach($path as $step) {
if(! isset($p[$step])) {
// add next level if it's absent
$p[$step] = [];
}
// go to next level
$p = &$p[$step];
}
}
demo

Related

Split array using list and array_chunk for dynamic requirements [duplicate]

This question already has answers here:
Split Array Into 3 Equal Columns With PHP
(3 answers)
Closed 1 year ago.
I am using list and array_chunk to split arrays. In my first example I split the array into four pieces using list.
I would like to change the number from 4 to say 8 and have it dynamically do this. Instead of manually creating it in the code. Is this possible ? I assume I could use variable naming as listed in my non working second example below.
How it works now :
list($inv0, $inv1, $inv2, $inv3) = array_chunk($val['inventory'], ceil(count($val['inventory']) / 4));
What I would like is to set something $i = 8 and have it automatically split into 8 chunks dynamically .
Something like :
$i = 8
list(${inv.0}, ${inv.1}, ${inv.2}, ${inv.3},${inv.4},${inv.5},${inv.6},${inv.7}) = array_chunk($val['inventory'], ceil(count($val['inventory']) / $i));
So based on my needs I can split the array into X pieces instead of hard coding it to 4 or 8 etc...
You can do a foreach to create the variables you want:
$array = ['a','b','c','d','e','f','g','h'];
$chunk = array_chunk($array,2);
foreach($chunk as $i => $data) {
${'inv'.$i} = $data;
}
print_r($inv0);
print_r($inv1);
die();
Output
Array ( [0] => a [1] => b )
Array ( [0] => c [1] => d )
There are ways, but I don't think it'd be a maintainable approach since you don't even know how many variables you'd need to process.
However, Felipe Duarte provides a working answer and there are some more over here : php how to generate dynamic list()?
But I'd agree with the top answer.
array_chunk already provides you with pretty much what you are looking for:
$chunks = array_chunk($val['inventory'], ceil(count($val['inventory']) / $i));
print_r($chunks);
// [[0] => ['', ''], [1] => ['','']...]
You can then access it via the indices (such as $chunks[0], $chunks[1]).

How to store strings into an array from a foreach loop?

To start off, I've read the handful of questions here asking similar questions but nothing that I could take example of and implement properly into my code. I've got an array that hold a few thousand numbers, they're the names of a file in a directory. I need to run a MySQL Query that searches for those file names, but I need all the individual queries to be in another array.
Here's my code to grab the filenames:
$dir = "C:/Users/EyeCandy-Brian/Desktop/jobs";
$files = array_diff(scandir($dir), array('..', '.'));
function truncate(&$fcn) {
$fcn = substr($fcn, 0, 6); // The original is '100100.dat', I only need the number
};
array_walk($files, "truncate");
The array looks like this:
2 => string '100100'
3 => string '100101'
4 => string '100102'
5 => string '100103'
// About 1,500+ Total
And here's my foreach loop with my declared variables:
$limit = 0; // This is for testing, stops after 5 iterations.
$qryArrNum = 2; // The index for the $files array, [0] & [1] were '.' & '..'
$count = 0; // Which index I want to store the string in, starting at [0]
$qry = array(); // I declare $qry as an array
foreach ($files as &$qry) {
$qry[$count++] = "SELECT * FROM `table` WHERE `sku` LIKE '%$files[$qryArrNum]%'";
++$qryArrNum;
if (++$limit == 5) {
break;
};
};
Here's where it gets wild. When using var_dump($qry); I get '1001S4' which shouldn't be. Running var_dump($files); The first five strings of the array are:
2 => string 'S00100'
3 => string '1S0101'
4 => string '10S102'
5 => string '100S03'
6 => string '1001S4'
Then following that are the expected strings from the filenames:
7 => string '100105'
8 => string '100106'
9 => string '100107'
// On for 1,500+ again
So my question is, how do I get $qry to be an array that contains a string, each string being the MySQL Query containing a search for the first value from $files, and the next string in the $qry array will search for the next value from $files. Also, why are the first handful values in $files completely different than what's expected?
NOTE: I understand that running a thousand plus MySQL Queries sequentially will murder my server, I'll use implode(); to combine them into one large query, I just need to figure this out initially.
Instead of running multiple queries you could use the mysql find_in_set().
https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_find-in-set
Once you have your files, use implode to convert to a string
$tmp = implode(",",$files);
Your sql statement would be:
$sql = "SELECT * FROM `table` WHERE FIND_IN_SET(`sku`,'{$tmp}')>0";
This will return all the matching items

php challenge: parse pseudo-regex

I have a challenge that I have not been able to figure out, but it seems like it could be fun and relatively easy for someone who thinks in algorithms...
If my search term has a "?" character in it, it means that it should not care if the preceding character is there (as in regex). But I want my program to print out all the possible results.
A few examples: "tab?le" should print out "table" and "tale". The number of results is always 2 to the power of the number of question marks. As another example: "carn?ati?on" should print out:
caraton
caration
carnaton
carnation
I'm looking for a function that will take in the word with the question marks and output an array with all the results...
Following your example of "carn?ati?on":
You can split the word/string into an array on "?" then the last character of each string in the array will be the optional character:
[0] => carn
[1] => ati
[2] => on
You can then create the two separate possibilities (ie. with and without that last character) for each element in the first array and map these permutations to another array. Note the last element should be ignored for the above transformation since it doesn't apply. I would make it of the form:
[0] => [carn, car]
[1] => [ati, at]
[2] => [on]
Then I would iterate over each element in the sub arrays to compute all the different combinations.
If you get stuck in applying this process just post a comment.
I think a loop like this should work:
$to_process = array("carn?ati?on");
$results = array();
while($item = array_shift($to_process)) {
$pos = strpos($item,"?");
if( $pos === false) {
$results[] = $item;
}
elseif( $pos === 0) {
throw new Exception("A term (".$item.") cannot begin with ?");
}
else {
$to_process[] = substr($item,0,$pos).substr($item,$pos+1);
$to_process[] = substr($item,0,$pos-1).substr($item,$pos+1);
}
}
var_dump($results);

PHP order/sort an array based on order of another array [duplicate]

This question already has answers here:
Custom key-sort a flat associative based on another array
(16 answers)
How can I sort arrays and data in PHP?
(14 answers)
Closed 9 years ago.
This should be fairly simple but my brain can't seem to process this at the moment. Hoping you can help :)
I have an array of posts that each have a tag, looks something like this:
Array(
[0] = Array('Computers', postObject),
[1] = Array('Sports', postObject),
[2] = Array('Computers', postObject),
[3] = Array('Business', postObject)
)
I was using asort() which seemed to sort the posts alphabetically, but I now need to sort the posts based on a specified order (stored in an array) that might have extra values.
Array(
[0] = 'Sports',
[1] = 'Fashion',
[2] = 'Business',
[3] = 'Computers',
[4] = 'Stocks'
)
I'm expecting the first array to be sorted like this:
Array(
[0] = Array('Sports', postObject),
[1] = Array('Business', postObject),
[2] = Array('Computers', postObject),
[3] = Array('Computers', postObject)
)
I don't think there is a simple php function to call, can you please advise ?
You can use the usort function, which sorts the array using a user-defined comparison function.
An untested solution can be:
$categories = array_flip($categories); // not needed by original solution
usort($posts, function($a, $b) use ($categories) {
// original solution:
// return array_search($a[0], $categories) > array_search($b[0], $categories);
// shameless CAP (copy-and-paste) from Mike Brant's answer
// actually, performs better, and I hope that he doesn't mind :)
return $categories[$a[0]] > $categories[$b[0]];
});
This solution is applicable for PHP v >= 5.3, since it uses anonymous functions and closures
If you are using PHP < 5.3, you can use ksort function, like this (again, untested):
$new_arr = array();
$categories = array_flip($categories);
foreach ($posts as $post) {
$new_arr[$categories[$post[0]]] = $post;
}
ksort($new_arr);
I would consider usort(). Example:
$array = array(...); // your multi-dimension array to sort
$sort_order_array = array(...); // your array defining sort order
$sort_order_array_flipped = array_flip($sort_order_array);
usort($array, function($a, $b) use ($sort_order_array_flipped) {
return $sort_order_array_flipped[$a[0]] > $sort_order_array_flipped[$b[0]];
});
Note that I flipped the sort order array in able to make it easy to lookup the order value (0, 1, 2) based on the value stored in the main array. This is actually computationaly faster than doing a key loop with every iteration of usort()

Get single column from 2d array [duplicate]

This question already has answers here:
Is there a function to extract a 'column' from an array in PHP?
(15 answers)
Closed 4 months ago.
This is my array
Array
(
[0] => Array
(
[sample_id] => 3
[time] => 2010-05-30 21:11:47
)
[1] => Array
(
[sample_id] => 2
[time] => 2010-05-30 21:11:47
)
[2] => Array
(
[sample_id] => 1
[time] => 2010-05-30 21:11:47
)
)
And I want to get all the sample_ids in one array. can someone please help ?
Can this be done without for loops (because arrays are very large).
$ids = array_map(function($el){return $el["sample_id"];}, $array);
Or in earlier versions:
function get_sample_id($el){return $el["sample_id"];}
$ids = array_map('get_sample_id', $array);
However, this is probably not going to be faster.
This is a problem I've had MANY times. There isn't an easy way to flatten arrays in PHP. You'll have to loop them adding them to another array. Failing that rethink how you're working with the data to use the original structure and not require the flatten.
EDIT: I thought I'd add a bit of metric information, I created an array $data = array(array('key' => value, 'value' => other_value), ...); where there were 150,000 elements in my array. I than ran the 3 typical ways of flattening
$start = microtime();
$values = array_map(function($ele){return $ele['key'];}, $data);
$end = microtime();
Produced a run time of: Run Time: 0.304405 Running 5 times averaged the time to just below 0.30
$start = microtime();
$values = array();
foreach ($data as $value) {
$values[] = $value['key'];
}
$end = microtime();
Produced a run time of Run Time: 0.167301 with an average of 0.165
$start = microtime();
$values = array();
for ($i = 0; $i < count($data); $i++) {
$values[] = $data[$i]['key'];
}
$end = microtime();
Produced a run time of Run Time: 0.353524 with an average of 0.355
In every case using a foreach on the data array was significantly faster. This is likely related to the overhead of the execution of a function for each element in the array for hte array_map() implementation.
Further Edit: I ran this testing with a predefined function. Below are the average numbers over 10 iterations for 'On the Fly' (defined inline) and 'Pre Defined' (string lookup).
Averages:
On the fly: 0.29714539051056
Pre Defined: 0.31916437149048
no array manitulation can be done without a loop.
if you can't see a loop, it doesn't mean it's absent.
I can make a function
array_summ($array) {
$ret=0;
foreach ($array as $value) $ret += $value;
return $ret;
}
and then call it array_summ($arr) without any visible loops. But don't be fooled by this. There is loop. Every php array function iterate array as well. You just don't see it.
So, the real solution you have to look for, is not the magic function but reducing these arrays.
From where it came? From database most likely.
Consider to make a database to do all the calculations.
It will save you much more time than any PHP bulit in function
I don't think you'll have any luck doing this without loops. If you really don't want to iterate the whole structure, I'd consider looking for a way to alter your circumstances...
Can you generate the sample_id data structure at the same time the larger array is created?
Do you really need an array of sample_id entries, or is that just a means to an end? Maybe there's a way to wrap the data in a class that uses a cache and a cursor to keep from iterating the whole thing when you only need certain pieces?

Categories