I have an array like this:
$arr = array(
'home.js' => new File(),
'view/index.html' => new File(),
'src/index.js' => new File(),
'src/libs/jquery.js' => new File()
);
Now I want to convert in a structure like this:
Array
(
[0] => Array
(
[text] => home.js
)
[1] => Array
(
[text] => view
[children] => Array
(
[0] => Array
(
[text] => index.html
)
)
)
[2] => Array
(
[text] => src
[children] => Array
(
[0] => Array
(
[text] => index.js
)
[1] => Array
(
[text] => libs
[children] => Array
(
[0] => Array
(
[text] => jquery.js
)
)
)
)
)
)
I tried for hours, with help of StackOverfow answers but I couldn't come up with a solution as all other questions have a different setup.
Edit:
What I got so far with the help of SO is (can't remember the exact answer though):
$out = array();
foreach($arr as $path => $file) {
$parts = explode('/', trim($path, '/'));
applyChain($out, $parts, $file);
}
function applyChain(&$arr, $parts, $value)
{
if (!is_array($parts)) {
return;
}
if (count($parts) == 0) {
$arr = $value;
} else {
array_shift($parts);
applyChain($arr[], $parts, $value);
}
}
print_r($out);
I don't know how exactly it works, especially the part applyChain($arr[] ...). It kinda works with the depth, but not with the file names. I get following output:
Array
(
[0] => File Object
(
)
[1] => Array
(
[0] => File Object
(
)
)
[2] => Array
(
[0] => File Object
(
)
)
[3] => Array
(
[0] => Array
(
[0] => File Object
(
)
)
)
)
There would be a solution in a few lines using explode() and eval(). But eval() is not considered clean, so lets try recursion:
<?php
class File {
}
$arr = array(
'home.js' => new File(),
'view/index.html' => new File(),
'src/index.js' => new File(),
'src/libs/jquery.js' => new File()
);
function sub($path) {
$rv = array();
$parts = explode('/', $path, 2); // strip off one level
$rv['text'] = $parts[0]; // put it into 'text' element
if (count($parts)>1) // is there anything left?
$rv['children'] = sub($parts[1]); // do the same for the rest of the path
return $rv;
}
$new = array();
foreach (array_keys($arr) as $file) {
$new[] = sub($file);
}
var_dump($new);
?>
But, as Peter commented, this creates seperate substructures even if the pathes have some part in common (like src/libs/jquery.js and src/libs/melon.js).
With the use of ugly eval() (which can be replaced later) I got the following code:
<?php
class File {
}
$arr = array(
'home.js' => new File(),
'view/index.html' => new File(),
'src/index.js' => new File(),
'src/libs/jquery.js' => new File(),
'src/libs/melon.js' => new File(),
);
// conversion
function sub($element) {
$rv = array();
foreach (array_keys($element) as $sub) {
$part['text'] = $sub;
if (is_array($element[$sub])) {
$part['children'] = sub($element[$sub]);
}
$rv[] = $part;
}
return $rv;
}
// create array with path file/folder names as keys
$new = array();
foreach (array_keys($arr) as $row) {
$def = '$new["'.preg_replace('&/&', '"]["', $row).'"] = 1;';
eval($def);
}
// run
$new2 = sub($new);
var_dump($new2);
?>
This outputs
array(3) {
[0]=>
array(1) {
["text"]=>
string(7) "home.js"
}
[1]=>
array(2) {
["text"]=>
string(4) "view"
["children"]=>
array(1) {
[0]=>
array(1) {
["text"]=>
string(10) "index.html"
}
}
}
[2]=>
array(2) {
["text"]=>
string(3) "src"
["children"]=>
array(2) {
[0]=>
array(1) {
["text"]=>
string(8) "index.js"
}
[1]=>
array(2) {
["text"]=>
string(4) "libs"
["children"]=>
array(2) {
[0]=>
array(1) {
["text"]=>
string(9) "jquery.js"
}
[1]=>
array(1) {
["text"]=>
string(8) "melon.js"
}
}
}
}
}
}
Related
I have a very big array, I will try to explain the issue in small examples:
Input:
Array (
[alert:accountDisabled:heading] => XYZ
[alert:accountDisabled:message] => XYZ
[alert:accountExpired:heading] => XYZ
[alert:accountExpired:message] => XYZ
[alert:errorResponse:heading] => XYZ
[button:back] => XYZ
)
What I need to get is:
array() {
["alert"]=> array(7) {
["accountDisabled"]=> array(2) {
["heading"]=> string(3) "XYZ"
["message"]=> string(3) "XYZ" }
["accountExpired"]=> array(2) {
["heading"]=> string(3) "XYZ"
["message"]=> string(3) "XYZ" }
["clientError"]=> array(2) {
["heading"]=> string(3) "XYZ"
["message"]=> string(3) "XYZ" }
["errorResponse"]=> array(1) {
["heading"]=> string(3) "XYZ" }
}
["button"]=> array(1) {
["back"]=> string(3) "XYZ"
}
As I said this is a very small example, but the point is to get hierarchy from keys from array number one, hierarchy is divided by this character in key :
I checked for those questions that look similar to this one but they are not helpful lat all
How to access and manipulate multi-dimensional array by key names / path?
Using a string path to set nested array data
SO please read carefully the description of my issue.
I tried to use it for each loop, and I succeed to divide elements from the key, for one element, but I'm not sure where I need to store those hierarchy values for the next elements, any ideas?
$input = [
'alert:accountDisabled:heading' => 'XYZ_1',
'alert:accountDisabled:message' => 'XYZ_2',
'alert:accountExpired:heading' => 'XYZ_3',
'alert:accountExpired:message' => 'XYZ_4',
'alert:errorResponse:heading' => 'XYZ_5',
'button:back' => 'XYZ_6'
];
$results = [];
foreach ($input as $key => $value) {
$arr = explode(':', $key);
$result = $value;
for ($i = count($arr) - 1; $i >= 0; $i--) {
$result = [ $arr[$i] => $result ];
}
$results[] = $result;
}
$result = array_merge_recursive(...$results);
print_r($result);
Output:
Array
(
[alert] => Array
(
[accountDisabled] => Array
(
[heading] => XYZ_1
[message] => XYZ_2
)
[accountExpired] => Array
(
[heading] => XYZ_3
[message] => XYZ_4
)
[errorResponse] => Array
(
[heading] => XYZ_5
)
)
[button] => Array
(
[back] => XYZ_6
)
)
Based on Lukas.j answer, you can use this function:
function parsePath($array, $separator = ':'){
$result = [];
foreach($array as $key => $value){
if(strpos($key, $separator) !== FALSE){
$keys = explode($separator, $key);
$inner_result = $value;
foreach (array_reverse($keys) as $valueAsKey) $inner_result = [$valueAsKey => $inner_result];
$result[] = $inner_result;
}
}
return array_merge_recursive(...$result);
}
How would I go about splitting this array to access and loop through each of these videos...
array(1) {
[0]=> array(2)
{
[0]=> array(3)
{
["title"]=> string(27) "A test title for this video"
["video_item"]=> string(70) "http://dev.test/wp-content/uploads/2014/01/1.Introduction3.mp4"
["video_image"]=> string(78) "http://dev.test/wp-content/uploads/2014/01/1.Introduction3_thumb23.jpg"
}
[1]=> array(3)
{
["title"]=> string(13) "asdf fads fad"
["video_item"]=> string(67) "http://dev.test/wp-content/uploads/2014/01/Spring-Mower.mp4"
["video_image"]=> string(75) "http://dev.test/wp-content/uploads/2014/01/Spring-Mower1_thumb6.jpg"
}
}
}
This is part of the code I am using but obviously not working
// this gets the array
$videos = get_post_meta( get_the_ID(), 'video_items', false );
$vid = array();
$img = array();
foreach( $videos as $video ) {
$vid[] = $video['video_item'];
$img[] = $video['video_image'];
}
You have an array within an array, so you need to access the first element before you start iterating through each array inside that
So just add this line after you get the array $videos = fullArray[0];
// this gets the array as you did in your original code block
$fullArray = get_post_meta( get_the_ID(), 'video_items', false );
//But then you actually needed to add the below line. This gets the first
//element of the array which happens to be an array and actually contains the array you
//originally wanted to iterate through
$videos = fullArray[0];
$vid = array();
$img = array();
foreach( $videos as $video ) {
$vid[] = $video['video_item'];
$img[] = $video['video_image'];
}
echo "video urls " . $vid . "\n";
echo "image urls " . $img;
Maybe you can use array_chunk to have it's pieces.
http://us2.php.net/manual/en/function.array-chunk.php
As said in the documentation:
<?php
$input_array = array('a', 'b', 'c', 'd', 'e');
print_r(array_chunk($input_array, 2));
print_r(array_chunk($input_array, 2, true));
?>
Will print
Array
(
[0] => Array
(
[0] => a
[1] => b
)
[1] => Array
(
[0] => c
[1] => d
)
[2] => Array
(
[0] => e
)
)
Array
(
[0] => Array
(
[0] => a
[1] => b
)
[1] => Array
(
[2] => c
[3] => d
)
[2] => Array
(
[4] => e
)
)
try this
foreach($array as $key => value)
{
if(is_array($value))
{
foreach($value as $k => $v)ev
{
foreach($v as $k1 => $v1)
{
echo $k1 .'=>'.$v1.PHP_EOL;
}
}
}
}
even better will be using a RecursiveIterator here
I have an array that looks like this:
array(3) {
[0]=>
array(2) {
[0]=>
string(10) "2012-11-14"
[1]=>
string(5) "3238"
}
[1]=>
array(2) {
[0]=>
string(10) "2012-11-13"
[1]=>
string(5) "3231"
}
[2]=>
array(2) {
[0]=>
string(10) "2012-11-13"
[1]=>
string(5) "3231"
}
I would like to write a foreach loop that would turn this array into:
array(2) {
[0]=>
array(1) {
"2012-11-14" => "3238"
}
[1]=>
array(1) {
"2012-11-13" => "3231"
}
So, basically, I would like to use the array element formatted as Y-M-D date as key to the second element in the array.
Given the following array...
$array = array(
0 => array(0 => "2012-11-14", 1 => "3238"),
1 => array(0 => "2012-11-13", 1 => "3231"),
2 => array(0 => "2012-11-13", 1 => "3231"),
);
putting it into a new array like this:
$new_array = array();
foreach ($array as $key => $item)
{
$new_array[$key][$item[0]] = $item[1];
}
print_r($new_array);
produces this output:
Array
(
[0] => Array
(
[2012-11-14] => 3238
)
[1] => Array
(
[2012-11-13] => 3231
)
[2] => Array
(
[2012-11-13] => 3231
)
)
My answer doesn't get rid of the duplicates, but the added dimension as specified in the original question means that duplicate dates as keys aren't an issue.
<?php
$data = array(
array("2012-11-14", "3238"),
array("2012-11-13", "3231"),
array("2012-11-13", "3231") // warning! when there are two record with same date, the second's count will be display
);
$result = array();
foreach ($data as $value) {
$result[$value[0]] = $value[1];
}
echo '<pre>';
print_r($result);
<?php
$newArray = array();
for($i=0;$i<count($arrayVariable);$i++)
{
$newArray[$arrayVariable[$i][0]] = $arrayVariable[$i][1];
}
echo '<pre>';print_r($newArray);echo '</pre>';
?>
Didn't test it but something like this should work in concept. Of course change arrayVariable to your variable.. but that aside.
You can use this code to get what you want:
$dates = array(
array("2012-11-01", "3238"),
array("2012-11-03", "4321")
);
print_r($dates);
$result = array();
foreach($dates as $value) {
$result[][$value[0]] = $value[1];
}
print_r($result);
The output will look like the requested form:
Array
(
[0] => Array
(
[2012-11-01] => 3238
)
[1] => Array
(
[2012-11-03] => 4321
)
)
Codepad demo: http://codepad.org/XAmUEdYh
However, I would personally prefer Aykut's solution. You would of course have a problem when you've got two records with the same date, but the overall array layout is a bit nicer ;).
Here is what I came up with:
<?php
$original = array(
array(
"2012-11-14",
"3238"
),
array(
"2012-11-13",
"3231"
),
array(
"2012-11-13",
"3231"
)
);
$newArray = array();
foreach($original as $subArray){
$newArray[] = array($subArray[0] => $subArray[1]);
}
var_dump($newArray);
I have some Problems reducing a multidimensional array into a normal one.
I have an input array like this:
Array
(
[0] => Array (
[0] => 17
[1] => 99
)
[1] => Array (
[0] => 17
[1] => 121
)
[2] => Array (
[0] => 99
[1] => 77
)
[3] => Array (
[0] => 45
[1] => 51
)
[4] => Array (
[0] => 45
[1] => 131
)
So I have a multidimensional array with some overlaps in the values (eg 17,99 and 17,121)
Now I want to have an output like this:
Array
(
[0] => Array (
[0] => 17
[1] => 99
[2] => 121
[3] => 77
)
[2] => Array (
[0] => 45
[1] => 51
[3] => 131
)
I want to save, which articles are the same in my database this way. The output array shpuld still be a multidimesional array, but every number on the second level should be unique in the array.
I'm trying to solve this for more than a week now, but I dont get it to work. I know it should be easy...but anyway - I dont get it :D
This is what i got so far:
$parity_sorted = array();
foreach($arr as $key => $a){
if(count($parity_sorted) > 0){
foreach($parity_sorted as $key2 => $arr_new){
if(in_array($a[0], $arr_new) || in_array($a[1], $arr_new)){
if(!in_array($a[0], $arr_new)){array_push($parity_sorted[$key2], $a[0]);}
if(!in_array($a[1], $arr_new)){array_push($parity_sorted[$key2], $a[1]);}
} else {
array_push($parity_sorted, array($a[0],$a[1]));
}
}
} else {
array_push($parity_sorted, array($a[0],$a[1]));
}
}
Did you maybe already solve problem like this or is there a much easier way? Maybe I just think too complicated (It's not my first try, but this code was the last try)
Any help would be appreciated. Thanks a lot
Here is my revised code given your comment and a DEMO of it working as expected. ( http://codepad.org/CiukXctS )
<?php
$tmp = array();
foreach($array as $value)
{
// just for claraty, let's set the variables
$val1 = $value[0];
$val2 = $value[1];
$found = false;
foreach($tmp as &$v)
{
// check all existing tmp for one that matches
if(in_array($val1, $v) OR in_array($val2, $v))
{
// this one found a match, add and stop
$v[] = $val1;
$v[] = $val2;
// set the flag
$found = true;
break;
}
}
unset($v);
// check if this set was found
if( ! $found)
{
// this variable is new, set both
$tmp[] = array(
$val1,
$val2,
);
}
}
// go trough it all again to ensure uniqueness
$array = array();
foreach($tmp as $value)
{
$array[] = array_unique($value); // this will eliminate the duplicates from $val2
}
ORIGIN ANSWER
The question is badly asked, but I'll attempt to answer what I believe the question is.
You want to gather all the pairs of arrays that have the same first value in the pair correct?
$tmp = array();
for($array as $value)
{
// just for claraty, let's set the variables
$val1 = $value[0];
$val2 = $value[1];
if(isset($tmp[$val1])) // we already found it
{
$tmp[$val1][] = $val2; // only set the second one
}
else
{
// this variable is new, set both
$tmp[$val1] = array(
$val1,
$val2,
);
}
}
// go trough it all again to change the index to being 0-1-2-3-4....
$array = array();
foreach($tmp as $value)
{
$array[] = array_unique($value); // this will eliminate the duplicates from $val2
}
Here is solution for common task.
$data = array(array(17,99), array(17,121), array(99,77), array(45,51), array(45,131));
$result = array();
foreach ($data as $innner_array) {
$intersect_array = array();
foreach ($result as $key => $result_inner_array) {
$intersect_array = array_intersect($innner_array, $result_inner_array);
}
if (empty($intersect_array)) {
$result[] = $innner_array;
} else {
$result[$key] = array_unique(array_merge($innner_array, $result_inner_array));
}
}
var_dump($result);
Try:
$arr = array(array(17,99),
array(17,121),
array(99,77),
array(45, 51),
array(45, 131)
);
foreach($arr as $v)
foreach($v as $m)
$new_arr[] = $m;
$array = array_chunk(array_unique($new_arr), 4);
var_dump($array);
Demo
It uses array_unique and array_chunk.
Output:
array(2) { [0]=>array(4) { [0]=> int(17) [1]=>int(99)
[2]=>int(121) [3]=> int(77) }
[1]=> array(3) { [0]=> int(45) [1]=>int(51)
[2]=>int(131) }
}
I think I get your problem. Let me have a crack at it.
$firstElems = array();
$secondElems = array();
foreach ( $arr as $v ) {
$firstElems[ $v[0] ] = array( $v[0] );
}
foreach ( $arr as $v ) {
$secondElems[ $v[1] ] = $v[0];
}
foreach ( $arr as $v ) {
if ( isset( $secondElems[ $v[0] ] ) ) {
array_push( $firstElems[ $secondElems[ $v[0] ] ], $v[1] );
}
else {
array_push( $firstElems[ $v[0] ], $v[1] );
}
}
foreach ( $firstElems as $k => $v ) {
if ( isset( $secondElems[ $k ] ) ) {
unset( $firstElems[ $k ] );
}
}
Output:
Array
(
[17] => Array
(
[0] => 17
[1] => 99
[2] => 121
[3] => 77
)
[45] => Array
(
[0] => 45
[1] => 51
[2] => 131
)
)
(Code examples: http://codepad.org/rJNNq5Vd)
I truly believe I understand you and if this is the case here is what you're looking for:
function arrangeArray($array) {
$newArray = array(array_shift($array));
for ($x = 0; $x < count($newArray); $x++) {
if (!is_array($newArray[$x])) {
unset($newArray[$x]);
return $newArray;
}
for ($i = 0; $i < count($newArray[$x]); $i++) {
foreach ($array as $key => $inArray) {
if (in_array($newArray[$x][$i], $inArray)) {
$newArray[$x] = array_unique(array_merge($newArray[$x], $inArray));
unset($array[$key]);
}
}
}
$newArray[] = array_shift($array);
}
}
Which will return:
array(2) {
[0]=>
array(4) {
[0]=>
int(17)
[1]=>
int(99)
[2]=>
int(121)
[4]=>
int(77)
}
[1]=>
array(3) {
[0]=>
int(45)
[1]=>
int(51)
[3]=>
int(131)
}
}
For:
var_dump(arrangeArray(array(
array(17,99),
array(17,121),
array(99,77),
array(45, 51),
array(45, 131),
)));
And:
array(1) {
[0]=>
array(6) {
[0]=>
int(17)
[1]=>
int(99)
[2]=>
int(121)
[3]=>
int(45)
[4]=>
int(77)
[6]=>
int(51)
}
}
For:
var_dump(arrangeArray(array(
array(17,99),
array(17,121),
array(99,77),
array(45, 51),
array(45, 17),
)));
I have pairs of items in an PHP array. Example:
<?php
$elements = array(
'tiger'=>'lion',
'car'=>'bike',
'lion'=>'zoo',
'truck'=>'plane'
);
?>
Now I want to combine these items so that all items which are connected in any way go to one group. Continuation of the example above:
<?php
$groups = array(
0=>array('tiger', 'lion', 'zoo'),
1=>array('car', 'bike'),
2=>array('truck', 'plane'
);
?>
Is this understandable? How could I achieve this?
I'm looking for a function which does this.
<?php
$elements = array(
'tiger' => 'lion',
'car' => 'bike',
'lion' => 'zoo',
'truck' => 'plane'
);
$groups = array();
foreach ($elements as $key => $val) {
$appended = false;
foreach ($groups as &$group) {
if ($group[0] == $key) {
array_unshift($group, $val);
$appended = true;
break;
}
}
if (!$appended) {
$groups[] = array($val, $key);
}
}
var_dump($groups);
Gives:
array(3) {
[0]=>
array(3) {
[0]=>
string(3) "zoo"
[1]=>
string(4) "lion"
[2]=>
string(5) "tiger"
}
[1]=>
&array(2) {
[0]=>
string(4) "bike"
[1]=>
string(3) "car"
}
[2]=>
array(2) {
[0]=>
string(5) "plane"
[1]=>
string(5) "truck"
}
}
Here's an O(n) solution:
$elements = array(
'tiger' => 'lion',
'car' => 'bike',
'lion' => 'zoo',
'truck' => 'plane'
);
$groups = array();
$sub = array();
$ignore = array();
foreach ( $elements as $key=>$value ) {
if ( isset($ignore[$key]) ) {
continue;
}
$sub = array($key, $value);
if ( isset($elements[$value]) ) {
$ignore[$value] = 1;
$sub[] = $elements[$value];
}
$groups[] = $sub;
}
print_r($groups);
Result:
Array
(
[0] => Array
(
[0] => tiger
[1] => lion
[2] => zoo
)
[1] => Array
(
[0] => car
[1] => bike
)
[2] => Array
(
[0] => truck
[1] => plane
)
)
The idea is simple:
Create a new array to hold your groups
Loop over the item array
Check if the group for the item exists in the group array - if it does not, create it
Put item in group