$assets = array(
'gp1' => array('XDEF390', 'XDEF302', '.RDS_EP01','XDEX11', '.RXL_EP01'),
'gp2' => array('XDEF390', 'XDEF300', 'XDEF302','XDEX11'),
'gp3' => array('XDEF395', 'XDEF300', 'XDEF302','XDEX11', '.RXL_EP01')
);
I need to remove every inner array if it contains an elements that starts with a dot . which means the asset is not reusable!
I will eventually have :
$assets = array(
'gp2' => array('XDEF390', 'XDEF300', 'XDEF302','XDEX11'),
);
$assets = array(
'gp1' => array('XDEF390', 'XDEF302', '.RDS_EP01','XDEX11', '.RXL_EP01'),
'gp2' => array('XDEF390', 'XDEF300', 'XDEF302','XDEX11'),
'gp3' => array('XDEF395', 'XDEF300', 'XDEF302','XDEX11', '.RXL_EP01')
);
foreach($assets as $outer_key => &$inner_assets)
foreach($inner_assets as $style)
if($style{0} == '.') {
unset($assets[$outer_key]);
continue 2;
}
var_dump($assets);
array(1) {
["gp2"]=>
array(4) {
[0]=>
string(7) "XDEF390"
[1]=>
string(7) "XDEF300"
[2]=>
string(7) "XDEF302"
[3]=>
string(6) "XDEX11"
}
}
$assets = array_filter($assets, function (array $asset) {
return !array_reduce($asset, function ($hasDot, $str) {
return $hasDot || $str[0] === '.';
});
});
<?php
$assets = array(
'gp1' => array('XDEF390', 'XDEF302', '.RDS_EP01','XDEX11', '.RXL_EP01'),
'gp2' => array('XDEF390', 'XDEF300', 'XDEF302','XDEX11'),
'gp3' => array('XDEF395', 'XDEF300', 'XDEF302','XDEX11', '.RXL_EP01')
);
foreach( $assets as $key=>$val){
foreach($val as $key1=>$val1){
if($val1[0] == '.') {
unset($assets[$key]);
}
}
}
print_r($assets);//Array ( [gp2] => Array ( [0] => XDEF390 [1] => XDEF300 [2] => XDEF302 [3] => XDEX11 ) )
?>
Related
I have an array like this :
array(3) {
["FL_1"] => array(3) {
["MIC_1"] => array(1) {
["SP_4"] => float(7)
}
["MIC_13"] => array(1) {
["SP_16"] => float(4)
}
["MIC_6"] => array(1) {
["SP_74"] => float(4)
}
}
["FL_2"] => array(2) {
["MIC_1"] => array(1) {
["SP_5"] => float(4)
}
["MIC_13"] => array(1) {
["SP_17"] => float(4)
}
["MIC_6"] > array(1) {
["SP_75"] => float(4)
}
}
["FL_3"] => array(2) {
["MIC_1"] => array(1) {
["SP_5"] => float(89)
}
["MIC_13"] => array(1) {
["SP_18"] => float(1)
}
["MIC_6"] > array(1) {
["SP_78"] => float(21)
}
}
}
For each FL_X, I need to keep only one MIC_X that follow the conditions below :
1- This MIC_X needs to be the same for each FL_X
2- This MIC_X needs to have the lowest possible SP_Xvalue
From this example I need to get the following array
array(3) {
["FL_1"] => array(1) {
["MIC_13"] => array(1) {
["SP_16"] => float(4)
}
}
["FL_2"] => array(1) {
["MIC_13"] => array(1) {
["SP_17"] => float(6)
}
}
["FL_3"] => array(1) {
["MIC_13"] => array(1) {
["SP_18"] => float(1)
}
}
}
Any help on how to do this would be much appreciated.
Thank you !
Here's one possible solution. It uses array_walk_recursive to find the SP_X key associated with the minimum SP_X value, then it traverses the array to find the MIC_X key associated with that SP_X key and value, and finally it uses array_map and array_filter to extract only those MIC_X key values from the original array:
// find the minimum SP_X value and its key
$min_sp = PHP_INT_MAX;
$min_key = '';
array_walk_recursive($array, function ($v, $k) use (&$min_sp, &$min_key) {
if ($v < $min_sp) {
$min_sp = $v;
$min_key = $k;
}
});
// find the MIC_X key corresponding to the min SP_X value
$mic_key = '';
foreach ($array as $fl) {
foreach ($fl as $mic => $sp) {
if (isset($sp[$min_key]) && $sp[$min_key] == $min_sp) {
$mic_key = $mic;
break 2;
}
}
}
// filter the array to get all the MIC_X values
$out = array_map(function ($fl) use ($mic_key) {
return array_filter($fl, function ($mic) use ($mic_key) {
return $mic == $mic_key;
}, ARRAY_FILTER_USE_KEY);
}, $array);
print_r($out);
Output:
Array
(
[FL_1] => Array
(
[MIC_13] => Array
(
[SP_16] => 4
)
)
[FL_2] => Array
(
[MIC_13] => Array
(
[SP_17] => 4
)
)
[FL_3] => Array
(
[MIC_13] => Array
(
[SP_18] => 1
)
)
)
Demo on 3v4l.org
I have the following multi-dimensional array and I need to iterate over it and wherever there is a duplicate name, a counter is added to the name.
[1] => Array
(
[0] => Array
(
[clientName] => John Smith
[clientType] => 0
[clientDOB] => 1980-10-14
)
)
[2] => Array
(
[0] => Array
(
[clientName] => John Smith
[clientType] => 0
[clientDOB] => 1970-01-01
)
[1] => Array
(
[clientName] => Jeremy White
[clientType] => 2
[clientDOB] => 2015-08-19
)
)
The code I'm using is this :
$finalNames = array_map(function ($item) use (&$namesCount) {
if (!isset($namesCount[$item['clientName']])) {
$namesCount[$item['clientName']] = 0;
}
$namesCount[$item['clientName']]++;
$item['clientName'] = $item['clientName'] . ' ' . $namesCount[$item['clientName']];
return $item;
}, $arrayOfTravellers);
array_map(function($item, $key) use ($namesCount, &$finalNames) {
$finalNames[$key]['clientName'] = $namesCount[$item['clientName']] == 1
? str_replace(' 1', '', $finalNames[$key]['clientName'])
: $finalNames[$key]['clientName'];
}, $arrayOfNames, array_keys($arrayOfTravellers));
Which is returning a bunch of errors such as :
Notice: Undefined index: clientName in /Applications/MAMP/htdocs/europatours/functions/reportsFunctions.php on line 330
My assumption is that the code is not fit for a multi-dimensional array. Can anyone help please? I need to retain the complete structure of the array only where there is a duplicate name, a counter is added such as John Smith 1, John Smith 2 whereas Jeremy White remains without a counter.
$arrayOfNames = array(
array('clientName' => 'John'),
array('clientName' => 'John'),
array('clientName' => 'Mary'),
array('clientName' => 'Mary'),
array('clientName' => 'Mary'),
array('clientName' => 'Tony'),
array('clientName' => 'Alex')
);
$namesCount = array();
$finalNames = array_map(function ($item) use (&$namesCount) {
if (!isset($namesCount[$item['clientName']])) {
$namesCount[$item['clientName']] = 0;
}
$namesCount[$item['clientName']]++;
$item['clientName'] = $item['clientName'] . ' ' . $namesCount[$item['clientName']];
return $item;
}, $arrayOfNames);
array_map(function($item, $key) use ($namesCount, &$finalNames) {
$finalNames[$key]['clientName'] = $namesCount[$item['clientName']] == 1
? str_replace(' 1', '', $finalNames[$key]['clientName'])
: $finalNames[$key]['clientName'];
}, $arrayOfNames, array_keys($arrayOfNames));
echo '<pre>';
var_dump($finalNames);
echo '</pre>';
The output would be:
array(7) {
[0]=>
array(1) {
["clientName"]=>
string(6) "John 1"
}
[1]=>
array(1) {
["clientName"]=>
string(6) "John 2"
}
[2]=>
array(1) {
["clientName"]=>
string(6) "Mary 1"
}
[3]=>
array(1) {
["clientName"]=>
string(6) "Mary 2"
}
[4]=>
array(1) {
["clientName"]=>
string(6) "Mary 3"
}
[5]=>
array(1) {
["clientName"]=>
string(4) "Tony"
}
[6]=>
array(1) {
["clientName"]=>
string(4) "Alex"
}
}
What about a combination of array_column and in_array when adding new values?
$records = array(); // your data
$name = 'John';
$i = 0;
do
{
$newName = $name . ( ($i == 0)? '' : ' '.$i );
$i++;
}
while (in_array($newName, array_column($records, 'clientName')));
$records[] = array('clientName' => $newName);
Due to performance issues you may want to call array_columns only once before the loop and store the results in a variable.
I have an array like this:
array(5) {
[0]=> array(1) { ["go-out"]=> string(7) "#0d4b77" }
[1]=> array(1) { ["cycling"]=> string(7) "#1472b7" }
[2]=> array(1) { ["diving"]=> string(7) "#1e73be" }
[3]=> array(1) { ["exploring"]=> string(7) "#062338" }
[4]=> array(1) { ["eating"]=> string(7) "#f79e1b" }
}
Let's say I have the first value like 'cycling', so how can I find the '#147217' value?
I have been trying a lot of combinations of
foreach ( $array as $key => list($key1 ,$val)) {
if ($key1 === $id) {
return $val;
}
}
But no luck.
Ideas?
You can use array_column -
array_column($your_array, 'cycling');
DEMO
You should also add the checks for key's existence.
you may still make one loop
$id = "cycling";
foreach($array as $val)
if(isset($val[$id])) echo $val[$id];
Demo on Evail.in
I have reformated tour code, try this, that works:
$array = array(
0 => array("go-out" => "#0d4b77"),
1 => array("cycling" => "#1472b7"),
2 => array("diving" => "#1e73be"),
3 => array("exploring" => "#062338"),
4 => array("eating" => "#f79e1b")
);
$id = "cycling";
foreach ($array as $key => $entry) {
if ($entry[$id]) {
echo $entry[$id];
}
}
$array = array(
0 => array("go-out" => "#0d4b77"),
1 => array("cycling" => "#1472b7"),
2 => array("diving" => "#1e73be"),
3 => array("exploring" => "#062338"),
4 => array("eating" => "#f79e1b")
);
$search = "cycling";
foreach ($array as $key => $entry)
if (isset($entry[$search]))
echo $entry[$search];
That works.
Nice day.
I have been puzzling with this problem for days, without any luck. I hope some of you can help.
From my database I get a list of files, which various information attached, including a virtual path. Some typical data is:
Array
(
[0] => Array
(
[name] => guide_to_printing.txt
[virtual_path] => guides/it
)
[1] => Array
(
[name] => guide_to_vpn.txt
[virtual_path] => guides/it
)
[2] => Array
(
[name] => for_new_employees.txt
[virtual_path] => guides
)
)
I wish to convert this into a hierarchical array structure from the virtual paths, so the output of the above should be:
Array
(
[0] => Array
(
[type] => dir
[name] => guides
[children] => Array
(
[0] => Array
(
[type] => dir
[name] => it
[children] = Array
(
[0] => Array
(
[type] => file
[name] => guide_to_printing.txt
)
[1] => Array
(
[type] => file
[name] => guide_to_vpn.txt
)
)
)
[1] => Array
(
[type] => file
[name] => for_new_employees.txt
)
)
)
)
Where the type property indicates if it is a directory or a file.
Can someone help with creating a function which does this conversion. It will be of great help. Thanks.
My own best solution so far is:
foreach($docs as $doc) {
$path = explode("/",$doc['virtual_path']);
$arrayToInsert = array(
'name' => $doc['name'],
'path' => $doc['virtual_path'],
);
if(count($path)==1) { $r[$path[0]][] = $arrayToInsert; }
if(count($path)==2) { $r[$path[0]][$path[1]][] = $arrayToInsert; }
if(count($path)==3) { $r[$path[0]][$path[1]][$path[2]][] = $arrayToInsert; }
}
Of course this only works for a depth of 3 in the directory structure, and the keys are the directory names.
Function
function hierarchify(array $files) {
/* prepare root node */
$root = new stdClass;
$root->children = array();
/* file iteration */
foreach ($files as $file) {
/* argument validation */
switch (true) {
case !isset($file['name'], $file['virtual_path']):
case !is_string($name = $file['name']):
case !is_string($virtual_path = $file['virtual_path']):
throw new InvalidArgumentException('invalid array structure detected.');
case strpos($virtual_path, '/') === 0:
throw new InvalidArgumentException('absolute path is not allowed.');
}
/* virtual url normalization */
$parts = array();
$segments = explode('/', preg_replace('#/++#', '/', $virtual_path));
foreach ($segments as $segment) {
if ($segment === '.') {
continue;
}
if (null === $tail = array_pop($parts)) {
$parts[] = $segment;
} elseif ($segment === '..') {
if ($tail === '..') {
$parts[] = $tail;
}
if ($tail === '..' or $tail === '') {
$parts[] = $segment;
}
} else {
$parts[] = $tail;
$parts[] = $segment;
}
}
if ('' !== $tail = array_pop($parts)) {
// skip empty
$parts[] = $tail;
}
if (reset($parts) === '..') {
// invalid upper traversal
throw new InvalidArgumentException('invalid upper traversal detected.');
}
$currents = &$root->children;
/* hierarchy iteration */
foreach ($parts as $part) {
while (true) {
foreach ($currents as $current) {
if ($current->type === 'dir' and $current->name === $part) {
// directory already exists!
$currents = &$current->children;
break 2;
}
}
// create new directory...
$currents[] = $new = new stdClass;
$new->type = 'dir';
$new->name = $part;
$new->children = array();
$currents = &$new->children;
break;
}
}
// create new file...
$currents[] = $new = new stdClass;
$new->type = 'file';
$new->name = $name;
}
/* convert into array completely */
return json_decode(json_encode($root->children), true);
}
Example
Case 1:
$files = array(
0 => array (
'name' => 'b.txt',
'virtual_path' => 'A/B//',
),
1 => array(
'name' => 'a.txt',
'virtual_path' => '././A/B/C/../..',
),
2 => array(
'name' => 'c.txt',
'virtual_path' => './A/../A/B/C//////',
),
3 => array(
'name' => 'root.txt',
'virtual_path' => '',
),
);
var_dump(hierarchify($files));
will output...
array(2) {
[0]=>
array(3) {
["type"]=>
string(3) "dir"
["name"]=>
string(1) "A"
["children"]=>
array(2) {
[0]=>
array(3) {
["type"]=>
string(3) "dir"
["name"]=>
string(1) "B"
["children"]=>
array(2) {
[0]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(5) "b.txt"
}
[1]=>
array(3) {
["type"]=>
string(3) "dir"
["name"]=>
string(1) "C"
["children"]=>
array(1) {
[0]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(5) "c.txt"
}
}
}
}
}
[1]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(5) "a.txt"
}
}
}
[1]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(8) "root.txt"
}
}
Case 2:
$files = array(
0 => array (
'name' => 'invalid.txt',
'virtual_path' => '/A/B/C',
),
);
var_dump(hierarchify($files));
will throw...
Fatal error: Uncaught exception 'InvalidArgumentException' with message 'absolute path is not allowed.'
Case 3:
$files = array(
0 => array (
'name' => 'invalid.txt',
'virtual_path' => 'A/B/C/../../../../../../../..',
),
);
var_dump(hierarchify($files));
will throw...
Fatal error: Uncaught exception 'InvalidArgumentException' with message 'invalid upper traversal detected.'
With something like this:
foreach ($array as $k => $v) {
$tmp = explode('/',$v['virtual_path']);
if(sizeof($tmp) > 1){
$array_result[$tmp[0]]['children'][$k]['type'] = 'file';
$array_result[$tmp[0]]['children'][$k]['name'] = $v['name'];
$array_result[$tmp[0]]['type'] = 'dir';
$array_result[$tmp[0]]['name'] = $v['name'];
}
}
I get an array like this on:
Array
(
[guides] => Array
(
[children] => Array
(
[0] => Array
(
[type] => file
[name] => guide_to_printing.txt
)
[1] => Array
(
[type] => file
[name] => guide_to_vpn.txt
)
)
[type] => dir
[name] => guide_to_vpn.txt
)
)
I know that's not exactly what you want but i think that can put you in the right direction.
Event though you should have tried something before you post here, I like your question and think it is a fun one. So here you go
function &createVirtualDirectory(&$structure, $path) {
$key_parts = $path ? explode('/', $path) : null;
$last_key = &$structure;
if (is_array($key_parts) && !empty($key_parts)) {
foreach ($key_parts as $name) {
// maybe directory exists?
$index = null;
if (is_array($last_key) && !empty($last_key)) {
foreach ($last_key as $key => $item) {
if ($item['type'] == 'dir' && $item['name'] == $name) {
$index = $key;
break;
}
}
}
// if directory not exists - create one
if (is_null($index)) {
$last_key[] = array(
'type' => 'dir',
'name' => $name,
'children' => array(),
);
$index = count($last_key)-1;
}
$last_key =& $last_key[$index]['children'];
}
}
return $last_key;
}
$input = array(
0 => array (
'name' => 'guide_to_printing.txt',
'virtual_path' => 'guides/it',
),
1 => array(
'name' => 'guide_to_vpn.txt',
'virtual_path' => 'guides/it',
),
2 => array(
'name' => 'for_new_employees.txt',
'virtual_path' => 'guides',
)
);
$output = array();
foreach ($input as $file) {
$dir =& createVirtualDirectory($output, $file['virtual_path']);
$dir[] = array(
'type' => 'file',
'name' => $file['name']
);
unset($dir);
}
print_r($output);
Provides the exact output you want
Here is simple way to do this with 2 recursive functions.
One function to parse one line of data.
Another to merge each parsed line of data.
// Assuming your data are in $data
$tree = array();
foreach ($data as $item) {
$tree = merge($tree, parse($item['name'], $item['virtual_path']));
}
print json_encode($tree);
// Simple parser to extract data
function parse($name, $path){
$parts = explode('/', $path);
$level = array(
'type' => 'dir',
'name' => $parts[0],
'children' => array()
);
if(count($parts) > 1){
$path = str_replace($parts[0] . '/', '', $path);
$level['children'][] = parse($name, $path);
}
else {
$level['children'][] = array(
'type' => 'file',
'name' => $name
);
}
return $level;
}
// Merge a new item to the current tree
function merge($tree, $new_item){
if(!$tree){
$tree[] = $new_item;
return $tree;
}
$found = false;
foreach($tree as $key => &$item) {
if($item['type'] === $new_item['type'] && $item['name'] === $new_item['name']){
$item['children'] = merge($item['children'], $new_item['children'][0]);
$found = true;
break;
}
}
if(!$found) {
$tree[] = $new_item;
}
return $tree;
}
I've found some very helpful answers but still have some problems.
I want to put different rows in global array, WITHOUT removing the other rows.
<?php
global $global_arr;
function first() {
///some code
global $global_arr;
$global_arr[] = array('first' =>
array('1' , '1', '1'));
}
function second() {
///some code
global $global_arr;
$global_arr[] = array('second' =>
array('2' , '2', '2'));
}
function third() {
///some code
global $global_arr;
$global_arr[] = array('third' =>
array('3' , '3', '3'));
}
first();
second();
third();
print_r($global_arr);
I want every of the functions to index the array and add rows respectevly
Thank you in advance!
Edit :
Thank to your help here is the working version :
function first($arr) {
$arr[] = array('first' =>
array(1, 1, 1));
return $arr;
}
function second($arr) {
$arr[] = array('second' =>
array(2, 2, 2));
return $arr;
}
$arr = array();
$arr = first($arr);
$arr = second($arr);
print_r($arr);
Output :
Array ( [0] => Array ( [first] => Array ( [0] => 1 [1] => 1 [2] => 1 ) ) [1] => Array ( [second] => Array ( [0] => 2 [1] => 2 [2] => 2 ) ) )
Any ideas how to be only :
Array ( [first] => Array ( [0] => 1 [1] => 1 [2] => 1) , [second] => Array([0] => 2, [1] => 2, [2] => 2))
?
$global_arr['third'][] = array('3.1' , '3.2', '3.3');
I don't get it - it's the same in/for all three functions.
BTW, I would use only one function like:
<?php
// $arg1 = "one", "two" or "three"
// $arg2 = ARRAY("data1.1", "data1.2", "data1.3") {
function myfunc($arg1, $arg2) {
if (!isset($my_arr)) { static $my_arr = ARRAY(); }
$my_arr[$arg1][] = $arg2;
return $my_arr; // Or code a getter and setter function
}
// Call, as often as you want - like:
myfunc('one', ARRAY('1.1', '1.2','1.3'));
myfunc('two', ARRAY('2.1', '2.2','2.3'));
$arr = myfunc('one', ARRAY('1.4', '1.5','1.6'));
print '<pre>';
var_dump($arr);
print '</pre>';
/* result:
array(2) {
["one"]=>
array(2) {
[0]=>
array(3) {
[0]=>
string(3) "1.1"
[1]=>
string(3) "1.2"
[2]=>
string(3) "1.3"
}
[1]=>
array(3) {
[0]=>
string(3) "1.4"
[1]=>
string(3) "1.5"
[2]=>
string(3) "1.6"
}
}
["two"]=>
array(1) {
[0]=>
array(3) {
[0]=>
string(3) "2.1"
[1]=>
string(3) "2.2"
[2]=>
string(3) "2.3"
}
}
}
*/
?>
Why you want to use global variable? You can simply write
function first($arr) {
$arr[] = array('first' =>
array('3' , '3', '3'));
return $arr;
}
function second($arr) {
$arr[] = array('second' =>
array('3' , '3', '3'));
return $arr;
}
function third($arr) {
$arr[] = array('third' =>
array('3' , '3', '3'));
return $arr;
}
$arr = array();
$arr = first($arr);
$arr = second($arr);
$arr = third($arr);