How can I transform
Array1
(
[0] => Some Text
[1] => Some Other Text (+£14.20)
[2] => Text Text (+£26.88)
[3] => Another One (+£68.04)
)
Into associative array like the one below:
Array2
(
[Some Text] => 0 //0 since there is no (+£val) part
[Some Other Text] => 14.20
[Text Text] => Text Text 26.88
[Another One] => 68.04
)
$newArray = array();
foreach( $oldArray as $str ) {
if( preg_match( '/^(.+)\s\(\+£([\d\.]+)\)$/', $str, $matches ) ) {
$newArray[ $matches[1] ] = (double)$matches[2];
} else {
$newArray[ $str ] = 0;
}
}
Something like this should work:
$a2 = array();
foreach ($Array1 as $a1) {
if (strpos($a1, '(') > 0) {
$text = substr($a1, 0, strpos($a1, '('));
$value = substr($a1, strpos($a1, '(')+3, strpos($a1, ')')-1);
} else {
$text = $a1;
$value = 0;
}
$a2[$text] = $value;
}
print_r($a2);
EDIT:
You can do this using explode method as well:
$a2 = array();
foreach ($Array1 as $a1) {
$a1explode = explode("(", $a1, 2);
$text = $a1explode[0];
if ($a1explode[1]) {
$value = substr($a1explode[1],3);
} else {
$value = 0;
}
$a2[$text] = $value;
}
print_r($a2);
Related
So I've got a list of paths, such as:
path/to/directory/file1
path/directory/file2
path2/dir/file3
path2/dir/file4
And I'd like to convert them into a multidimensional array like this:
array(
path => array(
to => array(
directory => array(
file1 => someValue
),
),
directory => array(
file2 => someValue
),
),
path2 => array(
dir => array(
file3 => someValue,
file4 => someValue
)
)
)
My first thought was to explode() the paths into segments and set up the array using a foreach loop, something like this:
$arr = array();
foreach ( $path as $p ) {
$segments = explode('/', $p);
$str = '';
foreach ( $segments as $s ) {
$str .= "[$s]";
}
$arr{$str} = $someValue;
}
But this doesn't work, and since the number of segments varies, I've kinda got stumped. Is there away to do this?
If somevalue can be an empty array:
<?php
$result = array();
$input = [
'path/to/directory/file1',
'path/directory/file2',
'path2/dir/file3',
'path2/dir/file4',
];
foreach( $input as $e ) {
nest( $result, explode('/', $e));
}
var_export($result);
function nest(array &$target, array $parts) {
if ( empty($parts) ) {
return;
}
else {
$e = array_shift($parts);
if ( !isset($target[$e]) ) {
$target[$e] = [];
}
nest($target[$e], $parts);
}
}
Here is the solution and a easy way
Just Reverse the whole exploded array and start creating array within a Array
$path[1] = "path/to/directory/file1";
$path[2] = "path/directory/file2";
$path[3] = "path2/dir/file3";
$path[4] = "path2/dir/file4";
$arr = array();
$b = array();
$k = 0;
foreach($path as $p) {
$c = 0;
$segments = explode('/', $p);
$reversed = array_reverse($segments);
foreach($reversed as $s) {
if ($c == 0) {
$g[$k] = array($s => "somevalue");
} else {
$g[$k] = array($s => $g[$k]);
}
$c++;
}
$k++;
}
var_dump($g);
Thanks so much VolkerK! Your answer didn't quite answer my question but it got me on the right track. Here's the version I ended up using to get it to work:
$result = array();
$input = [
'path/to/directory/file1' => 'someValue',
'path/directory/file2' => 'someValue',
'path2/dir/file3' => 'someValue',
'path2/dir/file4' => 'someValue',
];
foreach( $input as $e=>$val ) {
nest( $result, explode('/', $e), $val);
}
var_export($result);
function nest(array &$target, array $parts, $leafValue) {
$e = array_shift($parts);
if ( empty($parts) ) {
$target[$e] = $leafValue;
return;
}
if ( !isset($target[$e]) ) {
$target[$e] = [];
}
nest($target[$e], $parts, $leafValue);
}
I basically just added the somevalue as $leafValue and moved the base case around so that it would add the leafValue instead of a blank array at the end.
This results in:
Array
(
[path] => Array
(
[to] => Array
(
[directory] => Array
(
[file1] => someValue
)
)
[directory] => Array
(
[file2] => someValue
)
)
[path2] => Array
(
[dir] => Array
(
[file3] => someValue
[file4] => someValue
)
)
)
Thanks a lot!
It can be done without recursion
$path = array(
'path/to/directory/file1',
'path/directory/file2',
'path2/dir/file3',
'path2/dir/file4');
$arr = [];
$someValue = 'someValue';
foreach ( $path as $p ) {
$segments = explode('/', $p);
$str = '';
$p = &$arr;
foreach ( $segments as $s ) {
if (! isset($p[$s] ) ) $p[$s] = array();
$p = &$p[$s];
}
$p = $someValue;
}
print_r($arr);
I have an array that looks like this:
$array = array (
[level_1] => array (
[level_2] => array (
[level_3] => something
)
),
[level_12] => array (
[level_2] => somethingelse
),
[level_13] => array (
[level_22] => array (
[level_3] => something
)
),
);
The keys or values aren't always unique but the branches are.
And I have a string that looks like this:
$string = 'level_1-level_2-level_3';
Those are the keys for a branch.
And I need to somehow get the value from the array based on that string?
Like this:
$string_array = explode('-', $string);
$array[$string_array[0]][$string_array[1]][$string_array[2]] // something
But since the depth can be different this is not a viable solution...
Try this simple example, no need for a recursive function:
function get_item( $path, $array )
{
$paths = explode( '-', $path );
$result = $array;
foreach ( $paths as $path) {
isset( $result[$path] ) ? $result = $result[$path] : $result = false;
}
return $result;
}
$path = 'level_1-level_2-level_3';
echo get_item( $path, $array );
Try this:
$array = array (
'level_1' => array (
'level_2' => array (
'level_3' => 'something'
)
),
'level_12' => array (
'level_2' => 'somethingelse'
),
'level_13' => array (
'level_22' => array (
'level_3' => 'something'
)
),
);
$string = 'level_1-level_2-level_3';
$keys = explode('-', $string);
echo getItemIterative($keys, $array);
echo "\n";
echo getItemRecursive($keys, $array);
function getItemIterative($keys, $array)
{
$value = null;
foreach ($keys as $key) {
if ($value == null) {
$value = $array[$key];
}
if (is_array($value) && array_key_exists($key, $value)) {
$value = $value[$key];
}
}
return $value;
}
function getItemRecursive($keys, $array)
{
$key = array_shift($keys);
$value = $array[$key];
if (empty($keys)) {
return $value;
} else {
return getItemRecursive($keys, $value);
}
}
Make a $result variable which initially points to the root of the array, and loop through the levels of your $string_array 'til $result points at the leaf you were looking for.
// stuff you already have:
$array = array(...); // your big array
$string = 'level_1-level_2-level_3';
$string_array = explode('-', $string);
// new stuff:
$result = $array;
foreach ($string_array as $level) {
$result = $result[$level];
}
echo $result; // 'something'
Working example: Ideone
I'm having a problem with this. I have a string that looks like this:
coilovers[strut_and_individual_components][complete_strut][][achse]
And i want to convert it to to array that looks like this:
[coilovers] => Array
(
[strut_and_individual_components] => Array
(
[complete_strut]=> Array
(
[1] => Array
(
[achse] => some_value
)
[2] => Array
(
[achse] => some_value
)
)
)
)
is it possible?
Here is a quick implementation of a parser that will attempt to parse this string:
$input = 'coilovers[strut_and_individual_components][complete_strut][][achse]';
$output = array();
$pointer = &$output;
while( ($index = strpos( $input, '[')) !== false) {
if( $index != 0) {
$key = substr( $input, 0, $index);
$pointer[$key] = array();
$pointer = &$pointer[$key];
$input = substr( $input, $index);
continue;
}
$end_index = strpos( $input, ']');
$array_key = substr( $input, $index + 1, $end_index - 1);
$pointer[$array_key] = array();
$pointer = &$pointer[$array_key];
$input = substr( $input, $end_index + 1);
}
print_r( $output);
Essentially, we are iterating the string to find matching [ and ] tags. When we do, we take the value within the brackets as $array_key and add that into the $output array. I use another variable $pointer by reference that is pointing to the original $output array, but as the iteration goes, $pointer points to the last element added to $output.
It produces:
Array
(
[coilovers] => Array
(
[strut_and_individual_components] => Array
(
[complete_strut] => Array
(
[] => Array
(
[achse] => Array
(
)
)
)
)
)
)
Note that I've left the implementation of [] (an empty array key) and setting the values in the last index (some_value) as an exercise to the user.
Well I've found an another answer for it and it looks like this:
private function format_form_data(array $form_values) {
$reformat_array = array();
$matches = array();
$result = null;
foreach($form_values as $value) {
preg_match_all("/\[(.*?)\]/", $value["name"], $matches);
$parsed_product_array = $this->parse_array($matches[1], $value["value"]);
$result = array_push($reformat_array, $parsed_product_array);
}
return $result;
}
private function parse_array(array $values, $value) {
$reformat = array();
$value_carrier_key = end($values);
foreach (array_reverse($values) as $arr) {
$set_value_carrier = array($arr => $reformat);
if($arr == $value_carrier_key) {
$set_value_carrier = array($arr => $value);
}
$reformat = empty($arr) ? array($reformat) : $set_value_carrier;
}
return $reformat;
}
where array $form_values is:
Array
(
[name] => '[coilovers][strut_and_individual_components][complete_strut][][achse]',
[value] => 'some_value'
)
No. If you evaluate the string you will get invalid PHP.
If you want to store a PHP Array as string and get it loaded back as PHP Array, have a look at serialize and unserialize functions.
Of course you can build an array from your string, but you'll have to write a parser.
The solution I propose:
function format_form_data(array $data) {
$matches = array();
$result = [];
foreach($data as $key => $value) {
preg_match_all("/\[(.*?)\]/", $key, $matches);
$matches = array_reverse($matches[1]);
$matches[] = substr( $key, 0, strpos($key, '['));;
foreach ($matches as $match) {
$value = [$match=>$value];
}
$result = array_replace_recursive($result, $value);
}
return $result;
}
I have an array like this one :
Array
{
'property1.subproberty11' => "xxxxx",
'property1.subproberty12' => "yyyy",
'property2.subproberty21.subproperty211' => "zzzzzz",
'property2.subproberty21.subproperty212' => "wwwww",
'property2.subproberty22' => "yyyy",
....
That needs to be changed into something like :
Array
(
[property1] => Array
(
['subproberty11'] => "xxxxx"
['subproberty12'] => "yyyy"
)
[property2] => Array
(
[subproperty21] => Array
(
[subproperty211] => "zzzzzz"
[subproperty212] => "wwwwww"
)
['subproberty22'] => "yyyy"
)
...
I can't find a smart way of doing this, can someone help me ?
So, far, i have thought of this kind of algorithm :
$new_array = array();
foreach($old_array as $key => $value)
{
$subkeys = explode('.', $key);
$ss = array();
for($ii = 0 ; $ii < count($subkeys) ; $ii++)
{
$ss[] = "['".$subkeys[$ii]."']";
if ($ii < count($subkeys) -1)
eval('$new_array'.implode('',$ss).' = array();');
}
eval('$new_array'.implode('',$ss)." = '".$value."';');
}
I think we can do better, for example maybe we can avoid duplicating data by creating a new array ?
My working example:
function nestedKeysArray($input) {
$array = array();
foreach ($input as $key => $value) {
$keys = explode('.', $key);
if (count($keys) == 1) {
$array[$key] = $value;
} else {
$nested = &$array;
foreach ($keys as $k) {
if (!isset($nested[$k]))
$nested[$k] = array();
$nested = &$nested[$k];
}
$nested = $value;
}
}
return $array;
}
$input is array like first one from the question.
EDIT:
Changing original array, without copy:
function nestedKeysArray(&$input) {
foreach ($input as $key => $value) {
$keys = explode('.', $key);
if (count($keys) > 1) {
$nested = &$input;
foreach ($keys as $k) {
if (!isset($nested[$k]))
$nested[$k] = array();
$nested = &$nested[$k];
}
$nested = $value;
unset($input[$key]);
}
}
}
Some untested code, to give you the direction you could take.
Just loop through the array;
function SplitArray($properties) {
foreach($properties as $item=>$property) {
$properties[$item] = explode('.',$property, 2);
if(strpos($properties[$item][1], '.') === false)) {}
else {
$properties[$item][1] = SplitArray($properties[$item][1]);
}
}
return $properties;
}
is there a function out there to search in a array if it contains a part of a text
just like the jquery(':contains')
and then return the index it is in :)
here is an example to help you visualise it :)
$arr = array(
[0] => 'hello world',
[1] => 'foo',
[2] => 'bar',
);
$a = arr_contains('o',$arr); //returns array(1,0);
$b = arr_contains('fo',$arr);//return array(1);
$c = arr_contains('a',$arr);//return array(2);
$d = arr_contains('hello',$arr);//return array(0);
if recursively can be done would be a plus :)
Nope, you will have to write a custom function for matching by substring:
function arr_contains($str, $arr) {
$ret = array();
foreach ($arr as $k => $v) {
if (is_array($v)) {
if ($subarr = arr_contains($str, $v)) {
$ret[] = $subarr;
}
} else if (strpos($v, $str) !== false) {
$ret[] = $k;
}
}
return $ret;
}