I'm struggeling second day with transforming dot to tree structure.
Can anyone help?
$input = [
'inbox' => ['name' => 'Inbox'],
'inbox.first' => ['name' => 'First'],
'inbox.second' => ['name' => 'Second'],
'inbox.second.other' => ['name' => 'Second Other'],
'inbox.third.another' => ['name' => 'Third Another'],
];
$expectedOutput = [
'inbox' => [
'name' => 'Inbox',
'mailbox' => 'inbox',
'subfolders' => [
'first' => [
'name' => 'First',
'mailbox' => 'inbox.first',
'subfolders' => [],
],
'second' => [
'name' => 'Second',
'mailbox' => 'inbox.second',
'subfolders' => [
'other' => [
'name' => 'Second Other',
'subfolders' => [],
'mailbox' => 'inbox.second.other',
],
],
],
'third' => [
'subfolders' => [
'another' => [
'name' => 'Third Another',
'subfolders' => [],
'mailbox' => 'inbox.third.another',
],
],
],
],
],
];
You can check the laravel function Arr::set as a basis. If you bring your array to a format that matches the output of that function you can use it like so:
//This is the set function from https://github.com/laravel/framework/blob/5.5/src/Illuminate/Support/Arr.php#L510
function set(&$array, $key, $value)
{
if (is_null($key)) {
return $array = $value;
}
$keys = explode('.', $key);
while (count($keys) > 1) {
$key = array_shift($keys);
// If the key doesn't exist at this depth, we will just create an empty array
// to hold the next value, allowing us to create the arrays to hold final
// values at the correct depth. Then we'll keep digging into the array.
if (! isset($array[$key]) || ! is_array($array[$key])) {
$array[$key] = [];
}
$array = &$array[$key];
}
$array[array_shift($keys)] = $value;
return $array;
}
$input = [
'inbox' => ['name' => 'Inbox'],
'inbox.first' => ['name' => 'First'],
'inbox.second' => ['name' => 'Second'],
'inbox.second.other' => ['name' => 'Second Other'],
'inbox.third.another' => ['name' => 'Third Another'],
];
$newKeys = array_map(function ($key) {
$k = explode(".",$key);
$newkey = [];
foreach ($k as $segment) {
$newkey[] = $segment;
$newkey[] = "subfolders";
}
return implode(".",$newkey);
}, array_keys($input));
$input = array_combine($newKeys, array_map(function ($value,$key) {
return array_merge($value, ["mailbox"=>$key]);
},$input,array_keys($input)));
$res = [];
array_walk($input, function ($value,$key) use (&$res) {
set($res,$key,$value);
});
Demo: http://sandbox.onlinephpfunctions.com/code/9717e7606f099f1352a559c447b5225dd0d74f6c
Related
i have an array like this :
[
['external_account' => 'AAA', 'label' => 'Nbr de client', 'value' => 1],
['external_account' => 'AAA', 'label' => 'TTC', 'value' => 1],
['external_account' => 'BBB', 'label' => 'HT', 'value' => 0],
]
and i want to assemble data by external_account value and have an outpout (array) like this one
[
[
'external_account' => 'AAA',
'data' => [
['label' => 'Nbr de client', 'value' => 1],
['label' => 'TTC', 'value' => 1]
]
],
[
'external_account' => 'BBB',
'data' => [
['label' => 'HT', 'value' => 0]
]
]
]
my code so far :
foreach ($result as $current_key => $current_array) {
$assemble = [];
foreach ($result as $search_key => $search_array) {
if (
$current_key != $search_key &&
$current_array["external_account"] ==
$search_array["external_account"]
) {
$valeur = $current_array["external_account"];
array_push(
$assemble,
$current_array["label"],
$current_array["value"]
);
unset($result[$current_key]);
}
$data[] = ["external_account" => $valeur, "data" => $assemble];
}
}
please tell me what am doing wrong, am stuck on it.
The output of my code : enter link description here
It looks more complicated than it needs to be. For grouping problems like this, it's just a matter of using the thing you want to group by as a key as you build your result.
$result = [];
foreach ($data as $item) {
// extract the first key (external_account)
$account = array_shift($item);
// then use it as the key to group your data
$result[$account]['external_account'] = $account;
$result[$account]['data'][] = $item;
}
If you don't want to keep that key in your result, you can remove it with
$result = array_values($result);
I have an array
[
[
'title' => 'title0',
'data' => 'data0'
],
[
'title' => 'title1',
'data' => 'data1'
]
]
I need to get the output
[
'title' => ['title0','title1'],
'data' => ['data0', 'data1']
]
Please tell me how can I do this?
You didn't show any attempt, but I'm bored. Just loop the keys from the first sub-array and extract that column. No need to know what the keys are:
foreach(array_keys(reset($array)) as $key) {
$result[$key] = array_column($array, $key);
}
You could also do it this way:
foreach(reset($array) as $key => $val) {
$result[$key] = array_column($array, $key);
}
Or if it's as simple as those two known keys:
$result = ['title' => array_column($array, 'title'),
'data' => array_column($array, 'data')
];
You can do it like this
<?php
$shortedArray = [
'title' => [],
'data' => []
];
$mainArray = [
[
'title' => 'test0',
'data' => 'data0'
],
[
'title' => 'test1',
'data' => 'data1'
]
];
// Loop thru it
foreach($mainArray as $row){
$shortedArray['title'][] = $row['title'];
$shortedArray['data'][] = $row['data'];
}
print_r($shortedArray);
Hope this resolves your issue. Any query, let me know
I have a array (return from model):
$array = [
[
'id' => 1,
'name' => 'Name 1',
'date' => '2016'
'other' => '...'
],
[
'id' => 2,
'name' => 'Name 2',
'date' => '2016'
'other' => '...',
'children' =>
[
'id' => 3,
'name' => 'Name 3',
'date' => '2016'
'other' => '...',
'children' =>
[
....
]
]
],
];
I want to filter this array, just keep keys: id, name & children, like:
$array = [
[
'id' => 1,
'name' => 'Name 1'
],
[
'id' => 2,
'name' => 'Name 2'
'children' =>
[
'id' => 3,
'name' => 'Name 3'
'children' =>
[
....
]
]
],
];
I tried to keep important data, remove keys not 'id', 'name' & 'children', then convert this array to json.
Please help me! Thank you!
Recursive functions are your friends here!
Something like this:
function filter(array $array)
{
$filteredArray = array();
$allowedKeys = array('id', 'name', 'children');
foreach($array as $index => $element)
{
$filteredArray[$index] = array();
foreach ($element as $key => $value)
{
if(is_array($value) && in_array($key, $allowedKeys))
{
$filteredArray[$index][$key] = filter($value);
}
else
{
if(in_array($key, $allowedKeys))
{
$filteredArray[$index][$key] = $value;
}
}
}
}
return $filteredArray;
}
I have not tested it, so maybe you'll need to do some debugging.
Try this:
function minifyarray($item){
$newitem = [
'id' => $item['id'] ,
'name' => $item['name']
];
if(!empty($item['children']))
$newitem['children'] = array_map('minifyarray', $item['children']);
return $newitem;
}
$newarray = array_map('minifyarray', $array);
just make loop and unset unwanted stuff
function recursivelyRemoveUnwantedStuff($input){
if(array_key_exists('date',$input)){
unset($input['date']);
}
if(array_key_exists('other',$input)){
unset($input['other']);
}
if(array_key_exists('children',$input)){
$input['children'] = recursivelyRemoveUnwantedStuff($input['children']);
}
return $input;
}
and then
<?php outPutArray = recursivelyRemoveUnwantedStuff($inputArray); ?>
I am trying to make a multi-dimensional array build an array path adding the hr field so it looks like this:
I just can't figure out how to add the totals, nor create a sub-array so the dot notation in an option too. My goal is to get something like this:
[1] => [1][2][1][5][0][6] = 35 (the second child path "1")
[1] => [1][2][1][5][0][7] = 25
or Something like this:
array (
[children.0.children.0.children.0.total] = 20
[children.0.children.1.children.1.total] = 35
// etc
)
The complicated part is that it goes in different directions and I want to know what is the highest and lowest total based on the path:
==> Run Code Here or Copy/Paste
// -------------
// The Flattener
// -------------
function doit($myArray) {
$iter = new RecursiveIteratorIterator(new RecursiveArrayIterator($myArray));
$result = array();
foreach ($iter as $leafKey => $leafValue) {
$keys = array();
foreach (range(0, $iter->getDepth()) as $depth) {
$keys[] = $iter->getSubIterator($depth)->key();
}
$result[ join('.', $keys) ] = $leafValue;
}
return $result;
}
// -------------
// Example Tree
// -------------
$tree = [
'id' => 1,
'type' => 'note',
'data' => [],
'children' => [
[
'id' => 2,
'type' => 'wait',
'data' => [
'hr' => 10,
],
'children' => [
[
'id' => 3,
'type' => 'wait',
'data' => [
'hr' => 10,
],
'children' => [
'id' => 4,
'type' => 'exit',
'data' => [],
'children' => []
]
],
[
'id' => 5,
'type' => 'note',
'data' => [
'hr' => 10,
],
'children' => [
[
'id' => 6,
'type' => 'wait',
'data' => [
'hr' => 10,
],
'children' => []
],
[
'id' => 7,
'type' => 'exit',
'data' => [],
'children' => []
],
]
]
],
]
]
];
$result = doit($tree);
print_r($result);
This seems to work, I found it somewhere googling all day.
array_reduce(array_reverse($keys), function($parent_array, $key) {
return $parent_array ? [$key => $parent_array] : [$key];
}, null);
I have an array which looks something like this:
$a = [
1 => [
'title' => 'test',
'items' => [
5 => [
'title' => 'hello',
'items' => []
]
]
],
2 => [
'title' => 'second',
'items' => [
7 => [
'title' => 'hello in second',
'items' => []
]
]
],
3 => [
'title' => 'third',
'items' => [
10 => [
'title' => 'hello in third',
'items' => []
]
]
],
];
I need a way to extract parts of it by key no matter where they are in the tree. I've tried several ways but I'm not sure how efficient they are. If it helps I need to extract only those parts which have a numeric key. Any help will be much appreciated.
Try using the SPL iterators:
class KeyFinderFilterIterator extends FilterIterator {
private $search = null;
public function __construct($iterator, $search) {
$this->search = $search;
parent::__construct($iterator);
}
public function accept(){
return $this->key() == $this->search;
}
}
$it = new KeyFinderFilterIterator(
new RecursiveIteratorIterator(
new RecursiveArrayIterator($a),
RecursiveIteratorIterator::SELF_FIRST
),
10
);
foreach ($it as $key => $value) {
var_dump($value);
}