How to break string by separator into multidimensional array in PHP - php

I have a string 'value1/value2'. The required output is $_SESSION['value1']['value2']. i tried using explode and then array_reduce over explode values but with no success.
My code looks like
function set($key, $value){
/* code */
}
set('key1/key2', 'some_text');
required output like $_SESSION['key1']['key2'] = 'some_text';
key1/key2 is not fixed it may be 'key1' or 'key1/key2/key3' and so on.
Anyone be make fiddle of it is Highly appreciable.
Thanks

Accessing a value via a key-path string, as in your original question, using your original idea and let array_reduce do the work looks like:
$session = ['value1' => [ 'value2' => [ 'value3' => 'there you are!' ]]];
$path = explode('/', 'value1/value2/value3');
$val = array_reduce($path,
function(&$carry, $key) { return $carry[$key];},
$session);
echo $val
--> "there you are!"
Setting a value can be done e.g. like this, following the path by reference, creating arrays as needed:
function set($path, $value) {
$path = explode('/', $path);
$key = array_pop($path);
$arr = &$_SESSION;
foreach($path as $part) {
// carefull, this might lose values to accommodate
// the structure wanted with $path
(isset($arr[$part]) && is_array($arr[$part])) || ($arr[$part] = []);
$arr =& $arr[$part];
}
$arr[$key] = $value;
};

Try this
<?php
session_start();
$string = 'value1/value2';
$array = explode("/",$string);
$_SESSION[$array[0]][$array[1]] = "ccccccc";//$_SESSION['value1']['value2']

For a general case (i.e. for more than two pieces), you'll need to iterate over the segments, and incrementally index further into your target array:
<?php
$string = 'value1/value2/value3';
$_SESSION = ['value1' => ['value2' => ['value3' => 'My String']]];
$target = $_SESSION;
foreach (explode('/', $string) as $piece) {
$target =& $target[$piece];
}
echo $target; // My String

Related

array values to nested array with PHP

I'm trying to figure out how I can use the values an indexed array as path for another array. I'm exploding a string to an array, and based on all values in that array I'm looking for a value in another array.
Example:
$haystack['my']['string']['is']['nested'] = 'Hello';
$var = 'my#string#is#nested';
$items = explode('#', $var);
// .. echo $haystack[... items..?]
The number of values may differ, so it's not an option to do just $haystack[$items[0][$items[1][$items[2][$items[3]].
Any suggestions?
You can use a loop -
$haystack['my']['string']['is']['nested'] = 'Hello';
$var = 'my#string#is#nested';
$items = explode('#', $var);
$temp = $haystack;
foreach($items as $v) {
$temp = $temp[$v]; // Store the current array value
}
echo $temp;
DEMO
You can use a loop to grab each subsequent nested array. I.e:
$haystack['my']['string']['is']['nested'] = 'Hello';
$var = 'my#string#is#nested';
$items = explode('#', $var);
$val = $haystack;
foreach($items as $key){
$val = $val[$key];
}
echo $val;
Note that this does no checking, you likely want to check that $val[$key] exists.
Example here: http://codepad.org/5ei9xS91
Or you can use a recursive function:
function extractValue($array, $keys)
{
return empty($keys) ? $array : extractValue($array[array_shift($keys)], $keys) ;
}
$haystack = array('my' => array('string' => array('is' => array('nested' => 'hello'))));
echo extractValue($haystack, explode('#', 'my#string#is#nested'));

compact() variables into array by prefix?

Is this possible?
Like make an array with all the variables that have a certain prefix?
I don't need the keys just the values, but I guess I could use array_values on the array.
If you need to do this, it's probably not written very well to begin with, but, here's how to do it :)
$foobar = 'test';
$anothervar = 'anothertest';
$foooverflow = 'fo';
$barfoo = 'foobar';
$prefix = 'foo';
$output = array();
$vars = get_defined_vars();
foreach ($vars as $key => $value) {
if (strpos($key, $prefix) === 0) $output[] = $value;
}
/*
$output = array(
'test', // from $foobar
'fo', // from $foooverflow
);
*/
http://php.net/manual/en/function.get-defined-vars.php
my eyes are bleeding a little, but I couldn't resist a one liner.
print_r(iterator_to_array(new RegexIterator(new ArrayIterator(get_defined_vars()), '/^' . preg_quote($prefix) . '/', RegexIterator::GET_MATCH, RegexIterator::USE_KEY)));
If you're talking about variables in the global scope, you could do this with $GLOBALS[]:
$newarray = array();
// Iterate over all current global vars
foreach ($GLOBALS as $key => $value) {
// And add those with keys matching prefix_ to a new array
if (strpos($key, 'prefix_' === 0) {
$newarray[$key] = $value;
}
}
If you have lots and lots of variables in global scope, this is going to be slower in execution than manually adding them all to compact(), but faster to type out.
Addendum
I would just add (though I suspect you already know) that if you have the ability to refactor this code, you are better off to group the related variables together into an array in the first place.
This, my second answer, shows how to do this without making a mess of the global scope by using a simple PHP object:
$v = new stdClass();
$v->foo = "bar";
$v->scope = "your friend";
$v->using_classes = "a good idea";
$v->foo_overflow = "a bad day";
echo "Man, this is $v->using_classes!\n";
$prefix = "foo";
$output = array();
$refl = new ReflectionObject($v);
foreach ($refl->getProperties() as $prop) {
if (strpos($prop->getName(), $prefix) === 0) $output[] = $prop->getValue($v);
}
var_export($output);
Here's the output:
Man, this is a good idea!
array (
0 => 'bar',
1 => 'a bad day',
)

Convert delimited string into array key path and assign value

I have a string like this:
$string = 'one/two/three/four';
which I turn it into a array:
$keys = explode('/', $string);
This array can have any number of elements, like 1, 2, 5 etc.
How can I assign a certain value to a multidimensional array, but use the $keys I created above to identify the position where to insert?
Like:
$arr['one']['two']['three']['four'] = 'value';
Sorry if the question is confusing, but I don't know how to explain it better
This is kind of non-trivial because you want to nest, but it should go something like:
function insert_using_keys($arr, $keys, $value){
// we're modifying a copy of $arr, but here
// we obtain a reference to it. we move the
// reference in order to set the values.
$a = &$arr;
while( count($keys) > 0 ){
// get next first key
$k = array_shift($keys);
// if $a isn't an array already, make it one
if(!is_array($a)){
$a = array();
}
// move the reference deeper
$a = &$a[$k];
}
$a = $value;
// return a copy of $arr with the value set
return $arr;
}
$string = 'one/two/three/four';
$keys = explode('/', $string);
$arr = array(); // some big array with lots of dimensions
$ref = &$arr;
while ($key = array_shift($keys)) {
$ref = &$ref[$key];
}
$ref = 'value';
What this is doing:
Using a variable, $ref, to keep track of a reference to the current dimension of $arr.
Looping through $keys one at a time, referencing the $key element of the current reference.
Setting the value to the final reference.
You'll need to first make sure the key's exist, then assign the value. Something like this should work (untested):
function addValueByNestedKey(&$array, $keys, $value) {
$branch = &$array;
$key = array_shift($keys);
// add keys, maintaining reference to latest branch:
while(count($keys)) {
$key = array_pop($keys);
if(!array_key_exists($key, $branch) {
$branch[$key] = array();
}
$branch = &$branch[$key];
}
$branch[$key] = $value;
}
// usage:
$arr = array();
$keys = explode('/', 'one/two/three/four');
addValueByNestedKey($arr, $keys, 'value');
it's corny but:
function setValueByArrayKeys($array_keys, &$multi, $value) {
$m = &$multi
foreach ($array_keys as $k){
$m = &$m[$k];
}
$m = $value;
}
$arr['one']['two']['three']['four'] = 'value';
$string = 'one/two/three/four';
$ExpCheck = explode("/", $string);
$CheckVal = $arr;
foreach($ExpCheck AS $eVal){
$CheckVal = $CheckVal[$eVal]??false;
if (!$CheckVal)
break;
}
if ($CheckVal) {
$val =$CheckVal;
}
this will give u your value in array.

PHP Array values in string?

I have been looking around for a while in the PHP manual and can't find any command that does what I want.
I have an array with Keys and Values, example:
$Fields = array("Color"=>"Bl","Taste"=>"Good","Height"=>"Tall");
Then I have a string, for example:
$Headline = "My black coffee is cold";
Now I want to find out if any of the array ($Fields) values match somewhere in the string ($Headline).
Example:
Array_function_xxx($Headline,$Fields);
Would give the result true because "bl" is in the string $Headline (as a part of "Black").
I'm asking because I need performance... If this isn't possible, I will just make my own function instead...
EDIT - I'm looking for something like stristr(string $haystack , array $needle);
Thanks
SOLUTION - I came up with his function.
function array_in_str($fString, $fArray) {
$rMatch = array();
foreach($fArray as $Value) {
$Pos = stripos($fString,$Value);
if($Pos !== false)
// Add whatever information you need
$rMatch[] = array( "Start"=>$Pos,
"End"=>$Pos+strlen($Value)-1,
"Value"=>$Value
);
}
return $rMatch;
}
The returning array now have information on where each matched word begins and ends.
This should help:
function Array_function_xxx($headline, $fields) {
$field_values = array_values($fields);
foreach ($field_values as $field_value) {
if (strpos($headline, $field_value) !== false) {
return true; // field value found in a string
}
}
return false; // nothing found during the loop
}
Replace name of the function with what you need.
EDIT:
Ok, alternative solution (probably giving better performance, allowing for case-insensitive search, but requiring proper values within $fields parameter) is:
function Array_function_xxx($headline, $fields) {
$regexp = '/(' . implode('|',array_values($fields)) . ')/i';
return (bool) preg_match($regexp, $headline);
}
http://www.php.net/manual/en/function.array-search.php
that's what you looking for
example from php.net
<?php
$array = array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red');
$key = array_search('green', $array); // $key = 2;
$key = array_search('red', $array); // $key = 1;
?>

How to recursively create a multidimensional array?

I am trying to create a multi-dimensional array whose parts are determined by a string. I'm using . as the delimiter, and each part (except for the last) should be an array
ex:
config.debug.router.strictMode = true
I want the same results as if I were to type:
$arr = array('config' => array('debug' => array('router' => array('strictMode' => true))));
This problem's really got me going in circles, any help is appreciated. Thanks!
Let’s assume we already have the key and value in $key and $val, then you could do this:
$key = 'config.debug.router.strictMode';
$val = true;
$path = explode('.', $key);
Builing the array from left to right:
$arr = array();
$tmp = &$arr;
foreach ($path as $segment) {
$tmp[$segment] = array();
$tmp = &$tmp[$segment];
}
$tmp = $val;
And from right to left:
$arr = array();
$tmp = $val;
while ($segment = array_pop($path)) {
$tmp = array($segment => $tmp);
}
$arr = $tmp;
I say split everything up, start with the value, and work backwards from there, each time through, wrapping what you have inside another array. Like so:
$s = 'config.debug.router.strictMode = true';
list($parts, $value) = explode(' = ', $s);
$parts = explode('.', $parts);
while($parts) {
$value = array(array_pop($parts) => $value);
}
print_r($parts);
Definitely rewrite it so it has error checking.
Gumbo's answer looks good.
However, it looks like you want to parse a typical .ini file.
Consider using library code instead of rolling your own.
For instance, Zend_Config handles this kind of thing nicely.
I really like JasonWolf answer to this.
As to the possible errors: yes, but he supplied a great idea, now it is up to the reader to make it bullet proof.
My need was a bit more basic: from a delimited list, create a MD array. I slightly modified his code to give me just that. This version will give you an array with or without a define string or even a string without the delimiter.
I hope someone can make this even better.
$parts = "config.debug.router.strictMode";
$parts = explode(".", $parts);
$value = null;
while($parts) {
$value = array(array_pop($parts) => $value);
}
print_r($value);
// The attribute to the right of the equals sign
$rightOfEquals = true;
$leftOfEquals = "config.debug.router.strictMode";
// Array of identifiers
$identifiers = explode(".", $leftOfEquals);
// How many 'identifiers' we have
$numIdentifiers = count($identifiers);
// Iterate through each identifier backwards
// We do this backwards because we want the "innermost" array element
// to be defined first.
for ($i = ($numIdentifiers - 1); $i >=0; $i--)
{
// If we are looking at the "last" identifier, then we know what its
// value is. It is the thing directly to the right of the equals sign.
if ($i == ($numIdentifiers - 1))
{
$a = array($identifiers[$i] => $rightOfEquals);
}
// Otherwise, we recursively append our new attribute to the beginning of the array.
else
{
$a = array($identifiers[$i] => $a);
}
}
print_r($a);

Categories