I have a html array structure..
I output this array with foreach loops. (inside get_output functions)
Is it possible to output results without using foreach?
$schema = array(
array(
'tag' => 'div',
'class' => 'lines',
array(
'tag' => 'div',
array(
'tag' => 'span',
'style' => 'margin:10px; padding:10px',
'key' => '$key-countryname',
),
'key' => '$value-country',
),
array(
'tag' => 'div',
array(
'tag' => 'span',
'style' => 'margin:10px; padding:10px',
'key' => '$key-countryname',
),
'key' => '$value-country',
),
)
);
My function is using foreach loops to output results
function get_output($schema, $t = -2){
$t++; $tag = ""; $atts = array(); $keys = array(); $code = array();
foreach($schema as $k => $v){
if(is_array($v)){
$keys[] = get_output($v, $t);
} else {
switch($k){
case "tag": $tag = $v; break;
case "key": $keys[] = $v; break;
case "type": break;
default: $atts[$k] = $v; break;
}
}
}
if(0 < $t){ $code[] = "\n".str_repeat("\t", $t); }
if($tag){
$code[] = "<$tag"; foreach($atts as $k=>$v){ $code[] = ' '.$k.'="'.$v.'"'; } $code[] = ">";
$code = array(implode('', $code));
}
foreach($keys as $k){ $code[] = $k; }
if($tag){
$code[] = "\n".str_repeat("\t", $t);
$code[] = '</'.$tag.'>';
}
//print_r($code);
return implode("", $code);
}
while and for are perfectly valid ways to loop array:
$a = array(1,2,3); // indexed
$b = array(
'a' => 1,
'b' => 2,
'c' => 3
); // associative
echo '$a indexed with "for": <br />';
for ($i = 0; $i < count($a); $i++) {
echo $a[$i] . '<br />';
}
echo '$a indexed with "while": <br />';
$i = 0; // reset counter
while ($i < count($a)) {
echo $a[$i] . '<br />';
$i++;
}
echo '$b assoc with "for": <br />';
for ($i = 0; $i < count($a); $i++) {
echo key($b) . ' => ' . current($b) . '<br />';
next($b); // step forward
}
echo '$b assoc with "while": <br />';
reset($b); // rewind array cursor to start
while ($value = current($b)) {
echo key($b) . ' => ' . $value . '<br />';
next($b); // step forward
}
Also as you already implemented in your second code snippet, multi-dim array can be looped with recursion (though compared to nested loops it consumes more memory)
Related
This is what I'm doing:
for($i = 0; $i <= $max; $i++) {
if(isset($media[$i])) {
$combined[] = ["type" => "media", "value" => $media[$i]];
}
if(isset($content[$i])) {
$combined[] = ["type" => "content", "value" => $content[$i]];
}
if(isset($yt[$i])) {
$combined[] = ["type" => "youtube", "value" => $yt[$i]];
}
}
echo implode(', ', array_column($combined, 'media'));
Basically I need to echo all values of "media" as a single string with value separated commas.
Tried this too:
echo implode(', ', array_map(function ($entry) {
return $entry['media'];
}, $combined));
$string = '';
foreach ( $combined as $com ) {
if ( $com['type'] === 'media' ) {
$string .= $com['value'] . ',';
}
}
$string = rtrim( $string, ','); // remove trailing comma
echo $string;
I need this function to return an array. When I call the function it is printing the array, but when I use return $finalResult in the function, it is only printing the first array.
function readData($file)
{
$finalResult = array();
$inputText = file_get_contents($file);
$textLines = explode("\n", $inputText);
foreach ($textLines as $line)
{
$expLine = explode("\t", $line);
if (count($expLine) < 8)
{
# The line does not have enough items, deal with error
//echo "Item " . (isset($expLine[0]) ? $expLine[0]." " : "") . "ignored because of errors\n";
continue;
}
$finalResult = array(
"title" => $expLine[0],
"author" => $expLine[1],
"isbn" => $expLine[2],
"hardcover" => $expLine[3],
"hc-quantity" => $expLine[4],
"softcover" => $expLine[5],
"sc-quantity" => $expLine[6],
"e-book" => $expLine[7],
);
$arr = $finalResult;
print_r($arr);
}
}
Hi You mush merge or push array to $finalResult see sammple
function readData($file){
$finalResult = array();
$inputText = file_get_contents($file);
$textLines = explode("\n", $inputText);
foreach($textLines as $line) {
$expLine = explode("\t", $line);
if (count($expLine) < 8) {
# The line does not have enough items, deal with error
//echo "Item " . (isset($expLine[0]) ? $expLine[0]." " : "") . "ignored because of errors\n";
continue;
}
//Here []
$finalResult[] = array(
"title" =>$expLine[0],
"author" => $expLine[1],
"isbn" => $expLine[2],
"hardcover" => $expLine[3],
"hc-quantity" => $expLine[4],
"softcover" => $expLine[5],
"sc-quantity" => $expLine[6],
"e-book" => $expLine[7],
);
//$arr=$finalResult;
//print_r($arr);
}
return $finalResult;
}
As described in my comment above
function readData($file){
$arr = array();
$finalResult = array();
$inputText = file_get_contents($file);
$textLines = explode("\n", $inputText);
foreach($textLines as $line) {
$expLine = explode("\t", $line);
if (count($expLine) < 8) {
# The line does not have enough items, deal with error
//echo "Item " . (isset($expLine[0]) ? $expLine[0]." " : "") . "ignored because of errors\n";
continue;
}
$finalResult = array(
"title" =>$expLine[0],
"author" => $expLine[1],
"isbn" => $expLine[2],
"hardcover" => $expLine[3],
"hc-quantity" => $expLine[4],
"softcover" => $expLine[5],
"sc-quantity" => $expLine[6],
"e-book" => $expLine[7],
);
$arr=array_merge($arr, $finalResult);
}
return $arr;
}
I would like to display some array data in relation to a competition, each player is ranked by the number of points they have, however if a player has the same amount of points to somebody else they should both have the exact same ranking position.
For instance...
1st Bob 500pts
2nd Joe 350pts
3rd Tom 250pts
3rd Tim 250pts
5th Jay 100pts
In this instance, as Tom & Tim have the exact same number of points they should be joint third, making the next person down 5th (rather than 4th), can anyone suggest the best way to achieve this with a simple array similar to follows
array('Bob' => 500, 'Joe' => '350', 'Tom' => '250', 'Tim' => '250', 'Jay' => '100');
Can anyone suggest the 'cleanest' solution for achieving this
This code will work for you:
$array = array('Bob' => 500, 'Joe' => '350', 'Tom' => '250', 'Tim' => '250', 'Jay' => '100');
arsort($array, SORT_NUMERIC);
$previousPoints = null;
$position = $total = 1;
foreach($array as $name=>$points) {
if ($points != $previousPoints) {
$position = $total;
}
echo $position.' '.$name.' '.$points."\n";
$previousPoints = $points;
$total++;
}
Online demo here.
$ar = array(
'Bob' => 500,
'Tim' => '250',
'Joe' => '350',
'Tom' => '250',
'Jay' => '100'
);
arsort($ar, SORT_NUMERIC);
$i = 1;
$previous = 1;
$previousPosition = 1;
foreach($ar as $k => $v)
{
if($v === $previous)
{
//If the value now is the same as the previous value use the previous position
echo "Position: $previousPosition, $k : $v <br />";
}
else
{
echo "Position: $i, $k : $v <br />";
}
//Previous value
$previous = $v;
//Previous Position
$previousPosition = $i;
//Always increment the value
$i++;
}
Try below code:
$a = array('Bob' => 500, 'Joe' => '350', 'Tom' => '250', 'Tim' => '250', 'Jay' => '100');
arsort($a);
$rank = 1;
$index = 1;
$prevUserPoints = 0;
foreach($a as $name=>$points) {
if($points != $prevUserPoints) {
$rank = $index;
}
$index++;
echo $rank . ' ' . $name . ' ' . $points . "\n";
$prevUserPoints = $points;
}
For displaying 1 as 1st, 2 as 2nd etc, you can use something like below:
function ordSuffix($n) {
$str = "$n";
$t = $n > 9 ? substr($str,-2,1) : 0;
$u = substr($str,-1);
if ($t==1) return $str . 'th';
else switch ($u) {
case 1: return $str . 'st';
case 2: return $str . 'nd';
case 3: return $str . 'rd';
default: return $str . 'th';
}
}
example: echo ordSuffix(23); This prints 23rd
Just a basic and alternative point of view you might want to consider.
$arr = [
"Joe" => "350",
"Tom" => "250",
"Jay" => "200",
"Tim" => "250",
"Bob" => "500",
"John" => "250" ,
"Paul" => "251.40"
];
$rank = array();
array_walk($arr,function($v, $k) use (&$rank)
{
if(isset($rank[$v]))
{
$rank[$v][$k] = $v;
asort($rank[$v]); //alphabetical order John, Tim, Tom
} else
{
$rank[$v] = array($k => $v);
}
});
krsort($rank);
var_dump(array_values($rank));
I have an array like
$a = array(
'aaa' => "sample",
'bbb' => "sample2",
'ccc' => "adas",
'ddd' => "2",
'eee' => '2013-09-05',
'fff' => "false",
'ggg' => "893",
'qqq' => '2013-09-05',
'sss' => array(
"iii" => array(
'vvv' => "sample3",
'xxx' => 500,
)
),
'nnn' => '2013-09-05',
'mmm' => "Normal",
);
and I want to convert it to xml but witout using SimpleXMLElement or another function. That's why I have tried to do it with foreach. Here is my code ;
$data = '';
foreach ($a as $k => $v) {
if (is_array($k)) {
$data .= "<a:$k>" . $v . "</a:$k>";
foreach ($k as $j => $m) {
if (is_array($j)) {
foreach ($j as $s => $p) {
$data .= "<a:$s>" . $p . "</a:$s>";
}
} else {
$data .= "<a:$j>" . $m . "</a:$j>";
}
}
} else {
$data .= "<a:$k>" . $v . "</a:$k>";
}
}
but it's not working. I can make it work with hashmaps in another language but it must be in php. How can I do this.
Thanks.
You could try this:
function createXml($array, $level = 0)
{
$xml = ($level == 0) ? '<?xml version="1.0" encoding="ISO-8859-1"?>'.PHP_EOL : '';
$tab = str_pad('', $level, ' ', STR_PAD_LEFT);
foreach($array as $node => $value)
{
$xml .= "{$tab}<{$node}>";
if(!is_array($value))
{
$xml .= $value;
}
else
{
$level++;
$xml .= PHP_EOL.createXml($value, $level).$tab;
}
$xml .= "</{$node}>".PHP_EOL;
}
return $xml;
}
$xml = createXml($a);
echo $xml;
I have some PHP code I've been working on for a good few days now. I'm trying to generate a formatted list of rules from a flat array. I got help here before on how to turn the flat array into a tree array, but I'm having difficulty writing a recursive function that can go through it and successfully break it down at points at such depths where I'd like the rules to be members of an unordered list from the markup that gets printed.
<?php
$data = array(
'0' => 'Introduction',
'4' => 'General',
'4.1' => 'Chat',
'4.1.1' => 'Do',
'4.1.1.9' => 'This',
'4.1.1.10' => 'That',
'4.1.1.11' => 'Other',
);
$struct = array(
'children' => array()
);
foreach ($data as $ruleID => $content)
{
$parent =& $struct;
foreach (explode('.', $ruleID) as $val)
{
if (!isset($parent['children'][$val]))
{
$parent['children'][$val] = array(
'content' => '',
'children' => array()
);
}
$parent =& $parent['children'][$val];
}
$parent['content'] = $content;
}
$out = '';
$rules = array_pop($struct);
format_rule($rules);
var_dump($rules);
echo $out;
function format_rule($arr, $depth=0)
{
global $out;
echo "depth: $depth\n";
foreach($arr as $key => $val)
{
switch($depth)
{
case 0:
$out .= '<h1>'.$val['content']."</h1><br />\n";
break;
case 1:
$out .= '<h2>'.$val['content']."</h2><br />\n";
break;
case 2:
$out .= '<h3>'.$val['content']."</h3><br />\n";
break;
default:
$out .= '<li>'.$val['content']."</li>\n";
break;
}
if(isset($val['children']) && count($val['children']) > 0)
{
if($depth > 2)
{
$out .= '<ul>';
format_rule($val['children'], ++$depth);
$out .= '</ul>';
}
else
{
format_rule($val['children'], ++$depth);
}
}
}
}
The output at the moment is:
<h1>Introduction</h1><br />
<h1>General</h1><br />
<h2>Chat</h2><br />
<h3>Do</h3><br />
<li>This</li><br />
<li>That</li><br />
<li>Other</li><br />
Which is great, except from my code I'm pretty sure the section under 'Do' should have a <ul> around it.
change your code to :
if($depth >= 2)
note: remember the count starts at 0, not 1.
Try this:
<?php
$data = array(
'0' => 'Introduction',
'4' => 'General',
'4.1' => 'Chat',
'4.1.1' => 'Do',
'4.1.1.9' => 'This',
'4.1.1.10' => 'That',
'4.1.1.11' => 'Other',
);
function get_level($key){
return count(explode(".",$key));
}
function set_tag(&$array,$key,$item,&$ul_started){
$level = get_level($key);
switch($level){
case 1:
case 2:
case 3:
if($ul_started){
$array[$key] = "</ul><h".$level.">".$item."</h".$level."><br>";
$ul_started=false;
}else{
$array[$key] = "<h".$level.">".$item."</h".$level."><br>";
}
break;
default:
if(!$ul_started){
$array[$key] = "<ul><li><strong>".$item."</strong></li><br>";
$ul_started=true;
}else{
$array[$key] = "<li><strong>".$item."</strong></li><br>";
}
break;
}
}
$ul_started = false;
foreach($data as $key=>$item){
set_tag($data,$key,$item,$ul_started);
}
if($ul_started){
$keys = array_keys($data);
$data[$keys[count($data)-1]] .= "</ul>";
}
echo implode("",$data);
?>