php multidimensional array path segment combination loop - php

I am trying to figure a way to get this to work. But I have a hard time thinking out the logics.
I have this array:
Array
(
[0] => Array
(
[0] => news
[1] => {section}
[2] => {slug}
[3] => {*}
)
[1] => Array
(
[0] => {id}
[1] => {*}
)
[2] => Array
(
[0] => {date}
[1] => 25-07-1982
[2] => {section}
[3] => {slug}
[4] => {*}
)
)
That I need to convert to this result:
0 news/{id}/{date}
1 news/{id}/25-07-1982
2 news/{id}/{section}
3 news/{id}/{slug}
4 news/{id}/{*}
5 news/{*}/{date}
6 news/{*}/25-07-1982
7 news/{*}/{section}
8 news/{*}/{slug}
9 news/{*}/{*}
10 {section}/{id}/{date}
11 {section}/{id}/25-07-1982
12 {section}/{id}/{section}
13 {section}/{id}/{slug}
14 {section}/{id}/{*}
15 {section}/{*}/{date}
16 {section}/{*}/25-07-1982
17 {section}/{*}/{section}
18 {section}/{*}/{slug}
19 {section}/{*}/{*}
20 {slug}/{id}/{date}
21 {slug}/{id}/25-07-1982
22 {slug}/{id}/{section}
23 {slug}/{id}/{slug}
24 {slug}/{id}/{*}
25 {slug}/{*}/{date}
26 {slug}/{*}/25-07-1982
27 {slug}/{*}/{section}
28 {slug}/{*}/{slug}
29 {slug}/{*}/{*}
30 {*}/{id}/{date}
31 {*}/{id}/25-07-1982
32 {*}/{id}/{section}
33 {*}/{id}/{slug}
34 {*}/{id}/{*}
35 {*}/{*}/{date}
36 {*}/{*}/25-07-1982
37 {*}/{*}/{section}
38 {*}/{*}/{slug}
39 {*}/{*}/{*}
The input array could contain more than three keys, so the solution I'm looking for should be dynamic. And the result should have the same order as the result shown above.
Does someone know how to do this in a efficient way? Can someone give me a push in the right direction? Thanks a lot! :)

Sth like this
foreach ($array[0] as $val0 )
foreach ($array[1] as $val1 )
foreach ($array[2] as $val2 )
$newArray[] = "$val0/$val1/$val2";
EDIT: for variable array length
function recursive($array , $length = 0){
$retval =array();
if($length < count($array) -1){
foreach ($array[$length] as $val0 )
foreach (recursive($array, $length+1) as $val1)
$retval[] = "$val0/$val1";
}
else
{
foreach ($array[$length] as $val0 )
$retval[] = "$val0";
}
return $retval;
}
print_r(recursive($array));

Just because I like writing functions that mis/manage PHP arrays, I put this together, mainly because I was pretty sure you could avoid recursion — because the structure itself isn't recursive. (My head seems to think that is a rule, I'm sure someone somewhere can prove it wrong).
foreach ( array_reverse($array) as $sub ) {
if ( isset($rem) ) {
$ret = array();
foreach ( $sub as $itm ) {
foreach ( $rem as $val ) { $ret[] = "$itm/$val"; }
}
$rem = $ret;
}
else {
$rem = $sub;
}
}
The output found in $rem is as follows:
Array (
[0] => news/{id}/{date}
[1] => news/{id}/25-07-1982
[2] => news/{id}/{section}
[3] => news/{id}/{slug}
[4] => news/{id}/{*}
[5] => news/{*}/{date}
[6] => news/{*}/25-07-1982
[7] => news/{*}/{section}
[8] => news/{*}/{slug}
[9] => news/{*}/{*}
[10] => {section}/{id}/{date}
[11] => {section}/{id}/25-07-1982
[12] => {section}/{id}/{section}
[13] => {section}/{id}/{slug}
[14] => {section}/{id}/{*}
[15] => {section}/{*}/{date}
[16] => {section}/{*}/25-07-1982
[17] => {section}/{*}/{section}
[18] => {section}/{*}/{slug}
[19] => {section}/{*}/{*}
[20] => {slug}/{id}/{date}
[21] => {slug}/{id}/25-07-1982
[22] => {slug}/{id}/{section}
[23] => {slug}/{id}/{slug}
[24] => {slug}/{id}/{*}
[25] => {slug}/{*}/{date}
[26] => {slug}/{*}/25-07-1982
[27] => {slug}/{*}/{section}
[28] => {slug}/{*}/{slug}
[29] => {slug}/{*}/{*}
[30] => {*}/{id}/{date}
[31] => {*}/{id}/25-07-1982
[32] => {*}/{id}/{section}
[33] => {*}/{id}/{slug}
[34] => {*}/{id}/{*}
[35] => {*}/{*}/{date}
[36] => {*}/{*}/25-07-1982
[37] => {*}/{*}/{section}
[38] => {*}/{*}/{slug}
[39] => {*}/{*}/{*}
)
Also, for those that like their arrays multidimensional, this might come in handy (although I'd hate to think what the overheads are for such a code golfed version). Just to be clear, this second example doesn't create the string list as requested by the OP, but a hierarchical array structure instead.
foreach ( array_reverse($array) as $sub ) {
$rem = isset($rem)
? array_combine($sub, array_fill(0, count($sub), $rem))
: $sub
;
}
This generates (again in $rem):
Array (
[news] => Array (
[{id}] => Array (
[0] => {date}
[1] => 25-07-1982
[2] => {section}
[3] => {slug}
[4] => {*}
)
[{*}] => Array (
[0] => {date}
[1] => 25-07-1982
[2] => {section}
[3] => {slug}
[4] => {*}
)
)
[{section}] => Array (
[{id}] => Array (
[0] => {date}
[1] => 25-07-1982
[2] => {section}
[3] => {slug}
[4] => {*}
)
... and so on
Now if only PHP had a join_recursive that included keys.
(it would be almost pointless, save for helping with the above).

Related

Recursive PHP function is returning unexpected array

I have a hierarchical data that I put in a array that I call $dt. Than I have a array that store the relationship between these data that I call $in. I have create a function that has as parameter, the initial index, level, array $dt an the array $in. I was debugging the function but I am not find why the subclass is lost during the process. The complete code is:
$dt = array(
41=>array( "pk"=>41,"parentPk"=>30,"name"=>"car1"),
15=>array("pk"=>15,"parentPk"=>11,"name"=>"food" ),
70=>array("pk"=>70,"parentPk"=>30,"name"=>"car3" ),
18=>array("pk"=>18,"parentPk"=>15,"name"=>"food1" ),
49=>array("pk"=>49,"parentPk"=>30,"name"=>"car2" ),
20=>array( "pk"=>20,"parentPk"=>15,"name"=>"food2"),
30=>array("pk"=>30,"parentPk"=>11,"name"=>"car" )
);
echo "<pre>";
print_r($dt);
echo "</pre>";
$in=array(11=>array(15,30),15=>array(18,20),30=>array(41,49,70));
echo "<pre>";
print_r($in);
echo "</pre>";
function fn_tree($parent_id, $level,$dt,$in) {
if(is_null($parent_id)){
$parent_id ="NULL";
}
if (isset($in[$parent_id])) {
foreach ($in[$parent_id] as $id) {
$pk=$in[$parent_id];
$arrEnd[$id]=str_repeat("-", $level*2) .$dt[$id]["name"];
fn_tree($id, $level + 1,$dt,$in,$arrEnd);
}
}
return $arrEnd;
}
$arrEcho = fn_tree(11, 0, $dt, $in);
echo "<br>";
echo "result";
echo "<br>";
echo "<pre>";
print_r($arrEcho);
echo "</pre>";
$desired = array(
15=>"food",
18=>"food1",
20=>"food2",
30=>"car",
41=>"car1",
49=>"car2",
70=>"car3"
);
echo "<br>";
echo "desired";
echo "<br>";
echo "<pre>";
print_r($desired);
echo "</pre>";
So why the function is losting the sub-classes?
Output is:
Array data
(
[41] => Array
(
[pk] => 41
[parentPk] => 30
[name] => car1
)
[15] => Array
(
[pk] => 15
[parentPk] => 11
[name] => food
)
[70] => Array
(
[pk] => 70
[parentPk] => 30
[name] => car3
)
[18] => Array
(
[pk] => 18
[parentPk] => 15
[name] => food1
)
[49] => Array
(
[pk] => 49
[parentPk] => 30
[name] => car2
)
[20] => Array
(
[pk] => 20
[parentPk] => 15
[name] => food2
)
[30] => Array
(
[pk] => 30
[parentPk] => 11
[name] => car
)
)
Array relationship
(
[11] => Array
(
[0] => 15
[1] => 30
)
[15] => Array
(
[0] => 18
[1] => 20
)
[30] => Array
(
[0] => 41
[1] => 49
[2] => 70
)
)
result
Array
(
[15] => food
[30] => car
)
desired
Array
(
[15] => food
[18] => food1
[20] => food2
[30] => car
[41] => car1
[49] => car2
[70] => car3
)
The clue to your problem is/should have been "Undefined variable: arrEnd." If you aren't running in an environment where you can see this warning, you should try to set up such an environment. If you are running in such an environment, you should play close attention to this and all other warnings.
I'm not sure if it is the convention here to just give a clue or a whole answer, but proceeding on to give a fairly complete answer: it seems that you intended to pass arrEnd in by reference, but did not pass it in at all.
Also, I'm a little confused by your desired output. Don't you in fact desire something with double dashes showing hierarchy, as below?
Array
(
[15] => food
[18] => --food1
[20] => --food2
[30] => car
[41] => --car1
[49] => --car2
[70] => --car3
)

find non duplicated item in an array

I have two arrays built from different directories that contain file names stripped of extensions. I want to find the ones that don't make a pair thus I merged the array to obtain the array below. How can I find the only non duplicate item in an array?
Array
(
[0] => dbbackup_2014.09.03_07_06_27
[1] => dbbackup_2014.09.03_07_07_08
[2] => dbbackup_2014.09.03_07_13_33
[3] => dbbackup_2014.09.03_07_15_24
[4] => dbbackup_2014.09.03_07_21_57
[5] => dbbackup_2014.09.03_07_22_11
[6] => dbbackup_2014.09.03_08_40_35
[7] => dbbackup_2014.09.03_08_41_36
[8] => dbbackup_2014.09.03_08_43_38
[9] => dbbackup_2014.09.04_04_59_08
[10] => dbbackup_2014.09.03_07_06_27
[11] => dbbackup_2014.09.03_07_07_08
[12] => dbbackup_2014.09.03_07_13_33
[13] => dbbackup_2014.09.03_07_15_24
[14] => dbbackup_2014.09.03_07_21_57
[15] => dbbackup_2014.09.03_07_22_11
[16] => dbbackup_2014.09.03_08_40_35
[17] => dbbackup_2014.09.03_08_41_36
[18] => dbbackup_2014.09.03_08_43_38
)
Note: it is [9]
$a = array_flip(array_filter(array_count_values($a),function($item){
return $item == 1 ? true : false;
}));
print_r($a);
Output
Array
(
[1] => dbbackup_2014.09.04_04_59_08
)
Ideone
foreach($array as $data)
{
$values=explode("_",$data);
$output[$values[1]]++;
}
foreach($output as $date=>$number)
{
if($number==1)
echo $date;
}
Output:
2014.09.04
Fiddle

Re-order PHP array by middle key as start (Circular Sorting)

very basic question however I have had some trouble finding the answers on PHP.NET.
I have the following array:
Array (
[1] => Array
(
[1] => 4
[2] => 1
[3] => 5
[4] => 3
)
[2] => Array
(
[5] => 2
[6] => 8
[7] => 7
[8] => 6
)
[3] => Array
(
[9] => 10
[10] => 9
[11] => 12
[12] => 11
)
[4] => Array
(
[13] => 15
[14] => 16
[15] => 14
[16] => 13
)
)
I want the array to be re-ordered so that the key number 3 in the first series of the array becomes the first, then the rest to be re-ordered from there to eventually get the result of:
Array (
[3] => Array
(
[9] => 10
[10] => 9
[11] => 12
[12] => 11
)
[4] => Array
(
[13] => 15
[14] => 16
[15] => 14
[16] => 13
)
[1] => Array
(
[1] => 4
[2] => 1
[3] => 5
[4] => 3
)
[2] => Array
(
[5] => 2
[6] => 8
[7] => 7
[8] => 6
)
)
I am looking for a way to do this so I can define the array, then the first level key I need to sort by, and then it will return the array in this way.
The standard PHP keys didn't seem to offer something like this, so it would be good to be able to have a separate function such as $newArray = reorder_array($array, $key);
I don't require any sorting of the second level, only the initial 4 main / first level array sections.
You help is greatly appreciated as I have been sitting on this one for awhile without a clear and simple solution.
You re-ordering can be simply implemented with one foreach loop, like:
function reorderArray($array, $key)
{
$found = false;
foreach($array as $k=>$v)
{
$found = $found || $k===$key;
if(!$found)
{
unset($array[$k]);
$array[$k] = $v;
}
//else break can be added for performance issues
}
return $array;
}
with usage
$array=[1=>'foo', 4=>'bar', 9=>'baz', 'test'=>51];
var_dump(reorderArray($array, 9));
var_dump(reorderArray($array, 'test'));
var_dump(reorderArray($array, 'no_such_key'));//original array in result
-check this demo. If keys are consecutive numerics, however, this can be easily implemented with array_slice() calls.

Replace value in multi dimension array

I have array format like:
Array
(
[Australia] => Array
(
[0] => [1990,0.01],
[1] => [1991,0.02],
[2] => [1992,0.02],
[3] => [1993,0.02],
[4] => [1994,0.02],
[5] => [1995,0.02],
[6] => [1996,0.02],
[7] => [1997,0.02],
[8] => [1998,0.02],
[9] => [1999,0.02],
[10] => [2000,0.02],
[11] => [2001,0.02],
[12] => [2002,0.02],
[13] => [2003,0.02],
[14] => [2004,0.02],
[15] => [2005,0.02],
[16] => [2006,0.02],
[17] => [2007,0.02],
[18] => [2008,0.02],
[19] => [2009,empty],
[20] => [2010,empty],
[21] => [2011,empty],
[22] => [2012,empty],
[23] => [2013,empty],
[24] => [2014,empty],
[25] => [2015,empty]
)
[Pakistan] => Array
(
[0] => [1990,0.00],
[1] => [1991,0.00],
[2] => [1992,0.00],
[3] => [1993,0.00],
[4] => [1994,0.00],
[5] => [1995,0.00],
[6] => [1996,0.00],
[7] => [1997,0.00],
[8] => [1998,0.00],
[9] => [1999,0.00],
[10] => [2000,0.00],
[11] => [2001,0.00],
[12] => [2002,0.00],
[13] => [2003,0.00],
[14] => [2004,0.01],
[15] => [2005,0.01],
[16] => [2006,0.00],
[17] => [2007,0.00],
[18] => [2008,0.00],
[19] => [2009,empty],
[20] => [2010,empty],
[21] => [2011,empty],
[22] => [2012,empty],
[23] => [2013,empty],
[24] => [2014,empty],
[25] => [2015,empty]
)
)
and i want to replace 'empty' with 0 without change the array structure and elements position. I stuck how to do..
You can use array_walk_recursive function:
function replace_empty(&$item, $key) {
$item = str_replace('empty', '0', $item);
}
array_walk_recursive($your_array, 'replace_empty');
You could use the array_walk_recursive function, with a callback function that would replace empty by 0.
For example, considering your array is declared this way :
$myArray[0] = array(23, empty, 43, 12);
$myArray[1] = array(empty, empty, 53, 19);
Note : I supposed you made a typo, and your arrays are not containing only a string, but several sub-elements.
You could use this kind of code :
array_walk_recursive($myArray, 'replacer');
var_dump($myArray);
With the following callback functon :
function replacer(& $item, $key) {
if ($item === empty) {
$item = 0;
}
}
Note that :
the first parameter is passed by reference !
which means modifying it will modify the corresponding value in your array
I'm using the === operator for the comparison
And you'd get the following output :
array(
0 =>
array
0 => int 23
1 => int 0
2 => int 43
3 => int 12
1 =>
array
0 => int 0
1 => int 0
2 => int 53
3 => int 19)
I would foreach in both indices (not tested):
foreach($array as $country){
foreach($country as &$field){
if($field[1] == 'empty'){
$field[1] = 0;
}
}
}
(I assume empty is a string)
EDIT:
If this [1990,0.00] is not an array but a string, you could use str_replace instead
foreach($array as $country){
foreach($country as &$field){
$field = str_replace('empty', '0.00', $field);
}
}
}

get specific values of array not showing

This is what my array looks like :
Array (
[0] => SimpleXMLElement Object (
[key] => Array (
[0] => Track ID
[1] => Name
[2] => Artist
[3] => Album Artist
[4] => Composer
[5] => Album
[6] => Genre
[7] => Kind
[8] => Size
[9] => Total Time
[10] => Disc Number
[11] => Disc Count
[12] => Track Number
[13] => Year
[14] => Date Modified
[15] => Date Added
[16] => Bit Rate
[17] => Sample Rate
[18] => Play Count
[19] => Play Date
[20] => Play Date UTC
[21] => Artwork Count
[22] => Persistent ID
[23] => Track Type
[24] => Location
[25] => File Folder Count
[26] => Library Folder Count )
[integer] => Array (
[0] => 2056
[1] => 3732918
[2] => 230661
[3] => 1
[4] => 1
[5] => 1
[6] => 1993
[7] => 128
[8] => 44100
[9] => 3
[10] => 3439412487
[11] => 1
[12] => 5
[13] => 1 )
[string] => Array (
[0] => Eye of the Tiger
[1] => Survivor
[2] => Survivor
[3] => Frankie Sullivan/Jim Peterik
[4] => Greatest Hits
[5] => Rock
[6] => MPEG audio file
[7] => 772F0F53F195E705
[8] => File
[9] => file://localhost/Users/cameron/Music/iTunes/iTunes%20Media/Music/Survivor/Greatest%20Hits/01%20Eye%20of%20the%20Tiger.mp3 )
[date] => Array (
[0] => 2012-08-27T17:01:00Z
[1] => 2012-08-27T17:01:03Z
[2] => 2012-12-27T07:21:27Z ) )
that's 1 result, there is about 50 of them repeated.
I am trying to select the artist value in this case : Frankie Sullivan/Jim Peterik
please note: there is about 50 other results that come after this first one, so I would like to do a foreach to display all results.
any suggestions? I am stuck.this is the code I used to get these results:
$xml = simplexml_load_file('Library.xml');
$xmlx = $xml->dict->dict->dict->key;
$artist = $xmlx->xpath("//dict[key='Artist']");
echo "<pre>" . print_r($artist, true) . "</pre>";
It seems that you have an array of SimpleXMLElement,
so you can iterate over your array and use the SimpleXMLElement facilities.
Try:
foreach($yourArray as $simpleXmlElement)
{
// Retrieve the name
echo $simpleXmlElement->string[3];
}
Take a look at the documentation for more question: SimpleXMLElement
For your specific problem, assuming the key and string are synchronized, you can try:
// Loop on your array of SimpleXMLElement
foreach($yourArray as $simpleXmlElement)
{
// Initialize the position and found value
$position = 0;
$found = false;
// Loop on the sub array 'key' and search the 'Artist Album' position
foreach($simpleXmlElement->key as $index => $value)
{
if ($value == "Album Artist")
{
$found = true;
break;
}
// Not found, increment position
$position++;
}
// Retrieve the name if found the artist album key
if ($found)
echo $simpleXmlElement->string[$position];
}
As
[3] => Album Artist
will give the position 3
Then, when retrieving the string value, it will return Frankie Sullivan/Jim Peterik

Categories