How to build a Multidimensional array in PHP - php

I am trying to build a multidimensional array in PHP using an array of string that I am cutting up so the string of 1:wlrb#yahoo.com:7:8.35 becomes
"id": "1",
"email_address": "wlrb#yahoo.com",
"domain": "yahoo.com",
"number_of_orders": "7",
"total_order_value": "£8.35"
In JavaScript I would create an object containing the above values and put it into an array but what is the equivalent in PHP?
So far I have the below code which gives me
Array ( [0] => stdClass Object ( [id] => 1 [email] => wlrb#yahoo.com
[domain] => yahoo.com [number_of_orders] => 7 [total_order_value] =>
8.35 )
<?php
$data = file_get_contents('orderdata');
/* echo $data; */
$lines = explode("\n", $data);
array_splice($lines, 0, 8);
/* var_dump($lines); */
array_splice($lines, -3);
/* var_dump($lines); */
/* removes all NULL, FALSE and Empty Strings but leaves 0 (zero) values */
$lines = array_values(array_filter($lines, 'strlen'));
function arraySort($lines ,$i) {
$rep = new stdClass();
$rep->id = strId($lines, $i);
$rep->email = strEmail($lines, $i);
$rep->domain = strDomain($lines, $i);
$rep->number_of_orders = orderNo($lines, $i);
$rep->total_order_value = orderValue($lines, $i);
/* var_dump($rep); */
return $rep;
}
function strDomain($lines, $i) {
if($lines[$i] == null){
return "";
}
else {
$str = $lines[$i];
$splt = explode(':', $str);
$domain = explode('#', $splt[1]);
return $domain[1];
}
}
function strId($lines, $i) {
if($lines[$i] == null){
return "";
}
else {
$str = $lines[$i];
$splt = explode(':', $str);
return $splt[0];
}
}
function strEmail($lines, $i) {
if($lines[$i] == null){
return "";
}
else {
$str = $lines[$i];
$splt = explode(':', $str);
return $splt[1];
}
}
function orderNo($lines, $i) {
if($lines[$i] == null){
return "";
}
else {
$str = $lines[$i];
$splt = explode(':', $str);
return $splt[2];
}
}
function orderValue($lines, $i) {
if($lines[$i] == null){
return "";
}
else {
$str = $lines[$i];
$splt = explode(':', $str);
return '£' + $splt[3];
}
}
$reports = array();
$reps = array();
for($i = 0, $length = count($lines); $i < $length; ++$i) {
$reps = arraySort($lines, $i);
array_push($reports, $reps);
}
?>
but when I try to search the array with
$filteredArray =
array_filter($reports, function($element) use($search){
return isset($element['domain']) && $element['domain'] == $search;
});
I get the following error
Fatal error: Uncaught Error: Cannot use object of type stdClass as
array in phpData.php:110 Stack trace: #0
[internal function]: {closure}(Object(stdClass)) #1
phpData.php(111): array_filter(Array,
Object(Closure)) #2 {main} thrown in
phpData.php on line 110
Is this because of the use of $rep = new stdClass();in my arraySort function? If so what should I be using?

The easiest and shortest solution would be :
$value = "1:wlrb#yahoo.com:7:8.35";
$keys = array('id', 'email_address', 'number_of_orders', 'total_order_value');
$fused = array_combine($keys, explode(':', $value));
$fused['domain'] = strDomain($fused['email_address']); //using your "strDomain()" function
It will give you the array you want, except you won't have the £ sign in your order value.

you can use object obtention method like this:
$filteredArray =
array_filter($reports, function($element) use($search){
return isset($element->domain) && $element->domain == $search;
});

Related

Comma separated string to parent child relationship array php

I have a comma separated string like
$str = "word1,word2,word3";
And i want to make a parent child relationship array from it.
Here is an example:
Try this simply making own function as
$str = "word1,word2,word3";
$res = [];
function makeNested($arr) {
if(count($arr)<2)
return $arr;
$key = array_shift($arr);
return array($key => makeNested($arr));
}
print_r(makeNested(explode(',', $str)));
Demo
function tooLazyToCode($string)
{
$structure = null;
foreach (array_reverse(explode(',', $string)) as $part) {
$structure = ($structure == null) ? $part : array($part => $structure);
}
return $structure;
}
Please check below code it will take half of the time of the above answers:
<?php
$str = "sports,cricket,football,hockey,tennis";
$arr = explode(',', $str);
$result = array();
$arr_len = count($arr) - 1;
$prev = $arr_len;
for($i = $arr_len; $i>=0;$i--){
if($prev != $i){
$result = array($arr[$i] => $result);
} else {
$result = array ($arr[$i]);
}
$prev = $i;
}
echo '<pre>',print_r($result),'</pre>';
Here is another code for you, it will give you result as you have asked :
<?php
$str = "sports,cricket,football,hockey,tennis";
$arr = explode(',', $str);
$result = array();
$arr_len = count($arr) - 1;
$prev = $arr_len;
for($i = $arr_len; $i>=0;$i--){
if($prev != $i){
if($i == 0){
$result = array($arr[$i] => $result);
}else{
$result = array(array($arr[$i] => $result));
}
} else {
$result = array ($arr[$i]);
}
$prev = $i;
}
echo '<pre>',print_r($result),'</pre>';

Multidimensional Array search by string

I have a multidimensional array that's contains all user data , and I've build a function to get array value with the given key .
the problem is that the array is multidimensional array , and I don't know how many level .
this is the function
function getUserSessionData($key)
{
$arrKeys = explode('.', $key);
if(count($arrKeys) == 1){
if(isset($_SESSION['user_data'][$arrKeys[0]])){
return $_SESSION['user_data'][$arrKeys[0]];
}
}
else{
if(isset($_SESSION['user_data'][$arrKeys[0]][$arrKeys[1]])){
return $_SESSION['user_data'][$arrKeys[0]][$arrKeys[1]];
}
}
return 0;
}
and this is an example of the call.
getUserSessionData('profile.firstName');
The (.) indicates of level of the array .
the function is support only tow levels .. is there any way to enhance this function so it can support more than tow levels ??
Sure, use a looping structure:
function getUserSessionData($key) {
$parts = explode('.', $key);
$data = $_SESSION["user_data"];
while (count($parts) > 0) {
$part = array_shift($parts);
$data = $data[$part];
}
return $data;
}
Or independently of the session:
function resolveKey($array, $key) {
$parts = explode('.', $key);
while (count($parts) > 0) {
$part = array_shift($parts);
$array = $array[$part];
}
return $array;
}
echo resolveKey(array(
"foo" => array(
"bar" => array(
"baz" => "ipsum"
)
)
), "foo.bar.baz"); // "ipsum"
echo resolveKey($_SESSION["user_data"], 'profile.firstName');
Here's a PHP-Fiddle
function getUserSessionData($key){
$arrKeys = explode('.', $key);
$data = $_SESSION['user_data'];
foreach($arrKeys as $k){
if(isset($data[$k])) $data = $data[$k];
else return false;
}
return $data;
}
Example usage:
session_start();
$_SESSION['user_data'] = [];
$_SESSION['user_data']['user'] = [];
$_SESSION['user_data']['user']['name'] = [];
$_SESSION['user_data']['user']['name']['first'] = "robert";
echo getUserSessionData("user.name.first"); // echos "robert"
Thank you #Halcyon
you've been very helpful.
but I've modified your function to get it to work .
this is the new function
function getUserSessionData($key) {
$data = Yii::app()->session['account_data']['user_data'];
$parts = explode('.', $key);
while (count($parts) > 0) {
$part = $parts[0];
if(!isset($data[$part])){
return 0;
}
$data = $data[$part];
array_shift($parts);
}
return $data;
}

Multiple String Replace Based on Index

I need to replace multiple sections of a string based on their indices.
$string = '01234567890123456789';
$replacements = array(
array(3, 2, 'test'),
array(8, 2, 'haha')
);
$expected_result = '012test567haha0123456789';
Indices in $replacements are expected not to have overlaps.
I have been trying to write my own solution, split the original array into multiple pieces based on sections which needs to be replaced or not, and finally combine them:
echo str_replace_with_indices($string, $replacements);
// outputs the expected result '012test567haha0123456789'
function str_replace_with_indices ($string, $replacements) {
$string_chars = str_split($string);
$string_sections = array();
$replacing = false;
$section = 0;
foreach($string_chars as $char_idx => $char) {
if ($replacing != (($r_idx = replacing($replacements, $char_idx)) !== false)) {
$replacing = !$replacing;
$section++;
}
$string_sections[$section] = $string_sections[$section] ? $string_sections[$section] : array();
$string_sections[$section]['original'] .= $char;
if ($replacing) $string_sections[$section]['new'] = $replacements[$r_idx][2];
}
$string_result = '';
foreach($string_sections as $s) {
$string_result .= ($s['new']) ? $s['new'] : $s['original'];
}
return $string_result;
}
function replacing($replacements, $idx) {
foreach($replacements as $r_idx => $r) {
if ($idx >= $r[0] && $idx < $r[0]+$r[1]) {
return $r_idx;
}
}
return false;
}
Is there any more effective way to achieve the same result?
The above solution doesn't look elegant and feels quite long for string replacement.
Use this
$str = '01234567890123456789';
$rep = array(array(3,3,'test'), array(8,2,'haha'));
$index = 0;
$ctr = 0;
$index_strlen = 0;
foreach($rep as $s)
{
$index = $s[0]+$index_strlen;
$str = substr_replace($str, $s[2], $index, $s[1]);
$index_strlen += strlen($s[2]) - $s[1];
}
echo $str;

PHP transform array 'a', 'b', 'c' to 'a/b/c', 'a/b', 'a'

I have an uri and want to get an array of parts starting with full uri descent until I have only the first uri segment as part. I also have domain but the segments get stitched starting from the end back.
String 'a/b/c' to array('a/b/c', 'a/b', 'a')
String 'test.domain.com' to array('test.domain.com', 'domain.com', 'com')
Based on my initial method and the second method from the answers and a third method I like to know which one is the quickest and maybe there is a fourth method even better...
Method 1:
function explode_special($delimiter, $string, $reverse = false)
{
if (strpos($string, $delimiter) === false) return array($string);
$segments = explode($delimiter, $string);
if ( ! $reverse)
{
array_walk($segments, function($v, $k, $d) use(&$segments, &$delimiter) {
$d[$k] = implode($delimiter, array_slice($segments, 0, (count($segments) - $k)));
}, &$parts);
}
else
{
array_walk($segments, function($v, $k, $d) use(&$segments, &$delimiter) {
$d[$k] = implode($delimiter, array_slice($segments, $k));
}, &$parts);
}
return $parts;
}
Method 2:
function explode_special($delimiter, $string, $reverse = false)
{
if (strpos($string, $delimiter) === false) return array($string);
$segments = explode($delimiter, $string);
$parts = array();
while ($segments)
{
$parts[] = implode($delimiter, $segments);
if ($reverse)
{
array_shift($segments);
}
else
{
array_pop($segments);
}
}
return $parts;
}
Method 3:
function explode_special($delimiter, $string, $reverse = false)
{
if (strpos($string, $delimiter) === false) return array($string);
$parts = array($string);
for ($i = substr_count($string, $delimiter); $i > 0; $i--)
{
$parts[] = $string = $reverse
// ? trim(strstr($string, $delimiter), $delimiter)
? substr($string, strpos($string, $delimiter) + 1)
: substr($string, 0, strrpos($string, $delimiter));
}
return $parts;
}
Output:
// explode_special('/', 'a/b/c') = array('a/b/c', 'a/b', 'c');
// explode_special('.', 'test.domain.com', true) =
// array('test.domain.com', 'domain.com', 'com');
function multisplit($delim,$str) {
$parts = explode($delim,$str);
$arr = Array();
while($parts) {
$arr[] = implode($delim,$parts);
array_pop($parts);
}
return $arr;
}
With that function, you can just call multisplit("/","a/b/c"); and it will return ['a/b/c','a/b','a']. Similarly, call multisplit(".","test.domain.com"); and get ['test.domain.com','test.domain','test'].
I came up with the following
<?php
header("Content-type: text/plain"); //For display purposes only
/**
* Returns an array of strings with diminishing elements of $string according to $delimiter
*
* #param string $string The string
* #param string $delimiter The delimiter
*
* #return string[] Array of strings
*/
function degrading_split($string, $delimiter) {
$exploded = explode($delimiter, $string); //Array version of the string
$result = array(); //Initialize result array
foreach ($exploded as $key => $value) { //Iterate the array
$result[] = implode( #Implode...
$delimiter, #Using the original delimiter
array_slice($exploded, $key) #The complete $exploded array starting from the current $key
);
}
return $result;
}
print_r(degrading_split("a/b/c/d", "/"));
What you think about this with regex
function splitString($string,$delim) {
$arr = array();
preg_match_all('~['.$delim.']~U',$string,$delimCounter);
$arr[] = $string;
for ($i = 0;$i<count($delimCounter[0]);$i++) {
$string = $arr[] = preg_replace('~^[^.]*['.$delim.']~',"",$string);
}
return $arr;
}

Parsing Javascript (not JSON) in PHP

I have a php string containing the serialization of a javascript object :
$string = '{fu:"bar",baz:["bat"]}';
The actual string is far more complicated, of course, but still well-formed javascript. This is not standard JSON, so json_decode fails. Do you know any php library that would parse this string and return a php associative array ?
This sounded like a fun challenge, so I coded up a tiny parser :D
class JsParserException extends Exception {}
function parse_jsobj($str, &$data) {
$str = trim($str);
if(strlen($str) < 1) return;
if($str{0} != '{') {
throw new JsParserException('The given string is not a JS object');
}
$str = substr($str, 1);
/* While we have data, and it's not the end of this dict (the comma is needed for nested dicts) */
while(strlen($str) && $str{0} != '}' && $str{0} != ',') {
/* find the key */
if($str{0} == "'" || $str{0} == '"') {
/* quoted key */
list($str, $key) = parse_jsdata($str, ':');
} else {
$match = null;
/* unquoted key */
if(!preg_match('/^\s*[a-zA-z_][a-zA-Z_\d]*\s*:/', $str, $match)) {
throw new JsParserException('Invalid key ("'.$str.'")');
}
$key = $match[0];
$str = substr($str, strlen($key));
$key = trim(substr($key, 0, -1)); /* discard the ':' */
}
list($str, $data[$key]) = parse_jsdata($str, '}');
}
"Finshed dict. Str: '$str'\n";
return substr($str, 1);
}
function comma_or_term_pos($str, $term) {
$cpos = strpos($str, ',');
$tpos = strpos($str, $term);
if($cpos === false && $tpos === false) {
throw new JsParserException('unterminated dict or array');
} else if($cpos === false) {
return $tpos;
} else if($tpos === false) {
return $cpos;
}
return min($tpos, $cpos);
}
function parse_jsdata($str, $term="}") {
$str = trim($str);
if(is_numeric($str{0}."0")) {
/* a number (int or float) */
$newpos = comma_or_term_pos($str, $term);
$num = trim(substr($str, 0, $newpos));
$str = substr($str, $newpos+1); /* discard num and comma */
if(!is_numeric($num)) {
throw new JsParserException('OOPSIE while parsing number: "'.$num.'"');
}
return array(trim($str), $num+0);
} else if($str{0} == '"' || $str{0} == "'") {
/* string */
$q = $str{0};
$offset = 1;
do {
$pos = strpos($str, $q, $offset);
$offset = $pos;
} while($str{$pos-1} == '\\'); /* find un-escaped quote */
$data = substr($str, 1, $pos-1);
$str = substr($str, $pos);
$pos = comma_or_term_pos($str, $term);
$str = substr($str, $pos+1);
return array(trim($str), $data);
} else if($str{0} == '{') {
/* dict */
$data = array();
$str = parse_jsobj($str, $data);
return array($str, $data);
} else if($str{0} == '[') {
/* array */
$arr = array();
$str = substr($str, 1);
while(strlen($str) && $str{0} != $term && $str{0} != ',') {
$val = null;
list($str, $val) = parse_jsdata($str, ']');
$arr[] = $val;
$str = trim($str);
}
$str = trim(substr($str, 1));
return array($str, $arr);
} else if(stripos($str, 'true') === 0) {
/* true */
$pos = comma_or_term_pos($str, $term);
$str = substr($str, $pos+1); /* discard terminator */
return array(trim($str), true);
} else if(stripos($str, 'false') === 0) {
/* false */
$pos = comma_or_term_pos($str, $term);
$str = substr($str, $pos+1); /* discard terminator */
return array(trim($str), false);
} else if(stripos($str, 'null') === 0) {
/* null */
$pos = comma_or_term_pos($str, $term);
$str = substr($str, $pos+1); /* discard terminator */
return array(trim($str), null);
} else if(strpos($str, 'undefined') === 0) {
/* null */
$pos = comma_or_term_pos($str, $term);
$str = substr($str, $pos+1); /* discard terminator */
return array(trim($str), null);
} else {
throw new JsParserException('Cannot figure out how to parse "'.$str.'" (term is '.$term.')');
}
}
Usage:
$data = '{fu:"bar",baz:["bat"]}';
$parsed = array();
parse_jsobj($data, $parsed);
var_export($parsed);
Gives:
array (
'fu' => 'bar',
'baz' =>
array (
0 => 'bat',
),
)
Tested with these strings:
'{fu:"bar",baz:["bat"]}',
'{rec:{rec:{rec:false}}}',
'{foo:[1,2,[3,4]]}',
'{fu:{fu:"bar"},bar:{fu:"bar"}}',
'{"quoted key":[1,2,3]}',
'{und:undefined,"baz":[1,2,"3"]}',
'{arr:["a","b"],"baz":"foo","gar":{"faz":false,t:"2"},f:false}',
Pear Services_JSON will parse that string (tested version 1.31). But given that that is a JSON parser and that this isn't valid JSON you have no guarantee that future versions will still work.
I found out that the Yii-framework's CJSON::decode() function handles Javascript objects as well.
If you're not using Yii, you should be able to just use the source code
thank luttkens
the CJON::decode() class of the Yii-framework works perfectly !
require_once ($_SERVER['DOCUMENT_ROOT']."/phplib/CJSON.php");
$json = new CJSON();
$data = $json->decode('{ url : "/jslib/maps/marker/marker_red.png", height : 34, width : 20, anchorIcon : [5,25.5], anchorText : [0,2], }', true);
print_r( $data );
result :
Array
(
[url] => /jslib/maps/marker/marker_red.png
[height] => 34
[width] => 20
[anchorIcon] => Array
(
[0] => 5
[1] => 25.5
)
[anchorText] => Array
(
[0] => 0
[1] => 2
)
)
What about that library?
http://timwhitlock.info/tag/jparser/
I haven't tried it yet.

Categories