I’ve been failing (my whole day) in getting this structure formatted as a tree to present in this format, see picture attached.
as this has not parent and child the names of the key values strings like pattern_type_name act like parents and pattern_name are the child and under pattern_name are the marker_description to present the structure.
any help would be appreciated
below is the code I’m using:
$data='[ { "pattern_type_name":"Blood Sugar", "pattern_name":"TEST", "marker_description":"A/G ratio" }, { "pattern_type_name":"Blood Sugar", "pattern_name":"TEST", "marker_description":"Albumin" }, { "pattern_type_name":"Blood Sugar", "pattern_name":"TEST", "marker_description":"Alk Phos" }, { "pattern_type_name":"Red Blood Cell", "pattern_name":"TEST3", "marker_description":"A/G ratio" }, { "pattern_type_name":"Red Blood Cell", "pattern_name":"TEST3", "marker_description":"Albumin" }, { "pattern_type_name":"Red Blood Cell", "pattern_name":"TEST3", "marker_description":"Alk Phos" }, { "pattern_type_name":"Red Blood Cell", "pattern_name":"TEST3", "marker_description":"BUN" }, { "pattern_type_name":"Red Blood Cell", "pattern_name":"TEST3", "marker_description":"BUN/Creat ratio" }, { "pattern_type_name":"Red Blood Cell", "pattern_name":"TEST3", "marker_description":"Calcium" }, { "pattern_type_name":"Red Blood Cell", "pattern_name":"TEST3", "marker_description":"Chloride" }, { "pattern_type_name":"Cardivascular", "pattern_name":"TEST1", "marker_description":"EX3DWSQ" }, { "pattern_type_name":"Red Blood Cell", "pattern_name":"TEST4", "marker_description":"FEXTAFIX" } ]'; $related_patterns=json_decode($data,true); $arrlengng= count($related_patterns); $patternCount=0; $filteredItems=array(); $current_pattern_type_name=$related_patterns[0] ['pattern_type_name']; $current_pattern_name=$related_patterns[0]['pattern_name']; function filterArrayByKeyValue($array, $key, $keyValue){ return array_filter($array, function($value) use ($key, $keyValue) { return $value[$key] == $keyValue; }); } for($contloop=0;$contloop < $arrlengng;$contloop++){ if ($related_patterns[$contloop] ['pattern_type_name']==$current_pattern_type_name){ echo '==Pattern Type: '.$related_patterns[$contloop]['pattern_type_name'].' valor='.$contloop.'<br>'; echo '===Name: '.$related_patterns[$contloop]['pattern_name'].'<br>'; $current_pattern_name=$related_patterns[$contloop]['pattern_name']; $current_pattern_type_name=$related_patterns[$contloop]['pattern_type_name']; $filteredItems = filterArrayByKeyValue($related_patterns, 'pattern_name', $current_pattern_name); while($patternCount < count($filteredItems)){ echo '====marker_description: '.$filteredItems[$patternCount]['marker_description'].'<br>'; $patternCount++; } } $patternCount=0; echo $contloop.'------->'.$current_pattern_type_name.'------>'.$related_patterns[$contloop]['pattern_type_name'].'<br>';
}
Advertisement
Answer
When you need to translate data from one form to another, break it into steps:
- Discover the data’s structure
- How can you translate– how do the elements shift from one to the other
- Traverse the data
- Build the new structure
So the first thing I notice about the data is that it is already packaged in JSON, which is very convenient. How is it structured?
$data = '[ { "pattern_type_name":"Blood Sugar", "pattern_name":"TEST", "marker_description":"A/G ratio" }, // ... snip ]'; $table = json_decode($data); // illustrating with objects, it's easier to understand print_r($table);
yields:
Array ( [0] => stdClass Object ( [pattern_type_name] => Blood Sugar [pattern_name] => TEST [marker_description] => A/G ratio ) [1] => stdClass Object ( [pattern_type_name] => Blood Sugar [pattern_name] => TEST [marker_description] => Albumin ) // etc
So immediately I see that each row (the indexed array) is an object, with each row having the same properties. You could also picture it this way. with each property as a column:
type name description 0 Blood Sugar TEST AG ratio 1 Blood Sugar TEST Albumin 2 Blood Sugar TEST Alk Phos 3 Red Blood Cell TEST3 A/G ratio 4 Red Blood Cell TEST3 Albumin 5 Red Blood Cell TEST3 Alk Phos 6 Red Blood Cell TEST3 BUN 7 Red Blood Cell TEST3 BUN/Creat ratio // etc
If you think of each column’s value as a key, you could think of it this way (not using the row index):
$table['Blood Sugar']['TEST']['AG ratio ']; $table['Blood Sugar']['TEST']['Albumin']; $table['Blood Sugar']['TEST']['Alk Phos']; $table['Red Blood Cell']['TEST3']['A/G ratio']; $table['Red Blood Cell']['TEST3']['Albumin']; $table['Red Blood Cell']['TEST3']['Alk Phos']; $table['Red Blood Cell']['TEST3']['BUN']; $table['Red Blood Cell']['TEST3']['BUN/Creat ratio'];
This isn’t valid code, of course; it’s not assigning values. What’s important is the structure. (in fact the value doesn’t matter at all; it could just be a boolean true.)
Hopefully now the translation has become obvious; as you traverse $table
, the desired order is going to just fall in place:
$out = []; foreach($tempTable as $type=>$names) { $out[] = "-$type"; foreach($names as $name=>$descriptions) { $out[] = "--$name"; foreach($descriptions as $description=>$bool) { $out[] = "----$description"; } } } print join("n",$out);
Now that we have our plan, we need to prepare the data. Fortunately, the data is already in rows; all we need to do is make a new data structure with the values.
$table = json_decode($data, true); // using associative arrays this time $tempTable = []; foreach($tempTable as $row) { $type = $row['pattern_type_name']; $name = $row['pattern_name']; $desc = $row['marker_description']; $tempTable[$type][$name][$desc] = true; // value doesn't really matter }
Note, this is where Barmar’s suggestion comes into play; instead of building an intermediate structure, he suggests printing it as you go by comparing each iteration’s value against the previous. I’m accomplishing the same thing by making the new array dedupe the keys.
Putting it all together, we get this
$tempTable = []; $table = json_decode($data, true); // using associative arrays this time foreach($table as $row) { $type = $row['pattern_type_name']; $name = $row['pattern_name']; $desc = $row['marker_description']; $tempTable[$type][$name][$desc] = true; // value doesn't really matter // print "tempTable[][$type][$name][$desc] = true;n"; } // print_r($tempTable); // this is how I discovered that the index shouldn't be there! // die; $out = []; foreach($tempTable as $type=>$names) { $out[] = "-$type"; foreach($names as $name=>$descriptions) { $out[] = "--$name"; foreach($descriptions as $description=>$bool) { $out[] = "----$description"; } } } print join("n",$out);
Last note: I personally would not be satisfied with the nested foreach loops… the picket fence is a signal that it could be done better; but for this exercise I think it’s sufficient.