I am using php for this, but answers that are not language specific are also welcome.
I have several arrays of objects that I want to loop through and output in order. Each of the arrays have a different kind of object in them, but all of the objects have a unique order attribute.
For example:
$people = [{'name':'George','email':'George#test.com','order':'2'},{'name...];
$sandwiches = [{'type':'bacon','rating':'8/10','order':'1'},{'type...];
$restaurants = ....
$chefs = ...
...
What is the most efficient way to loop through them in order?
Assuming I can determine the maximum order I figured I could do something like:
for($i=0; $i< $maximumOrder; $i++)
{
for($j=0; $j< count($people); $j++)
{
if($people[$j]->order == $i)
{
//Do the things I want to do
break;
}
}
for($j=0; $j< count($sandwiches); $j++)
{
if($sandwiches[$j]->order == $i)
{
//Do the things I want to do
break;
}
}
for($j=0; $j< count($restaurants); $j++)
{
.....
}
But this isn't very good because even if the item with the desired order is found in people it will still continue looping through all the other arrays. I could just add a Boolean variable to show if the desired item has already been found (see below), but I am sure there are better ways to do this.
for($i=0; $i< $maximumOrder; $i++)
{
$found = false;
for($j=0; $j< count($people); $j++)
{
if($people[$j]->order == $i)
{
//Do the things I want to do
$found = true;
break;
}
}
if(!$found == true)
{
for($j=0; $j< count($sandwiches); $j++)
{
if($sandwiches[$j]->order == $i)
{
//Do the things I want to do
$found = true;
break;
}
}
}
if(!$found == true)
{
for($j=0; $j< count($restaurants); $j++)
{
.....
}
The below is based on #Victory's answer, with the addition of an elseif statement, to stop the while loop if it goes passed the desired order number (given these are now sorted arrays). This I believe should increase efficiency (at least with big arrays), but please correct me if I am wrong?
function orderArrayByOrder($a,$b)
{
return ($a->order < $b->order) ? -1 : 1;
}
$a1 = usort($people, "orderArrayByOrder");
$a2 = usort($sandwiches, "orderArrayByOrder");
$a3 = usort($restaurants, "orderArrayByOrder");
$c1 = count($a1)
$c2 = count($c2)
$c3 = count($c3)
$i1 = 0
$i2 = 0
$i3 = 0
// itertor over order
for ($curOrder ... $maxorder)
{
while ($i1 < $c1)
{
if($a1[$i1]->order == $curOrder)
{
//Do what I need to do
break;
}
elseif($a1[$i1]->order > $curOrder)
{
//We know the order won't exist in this array.
break;
}
$i1++;
}
while ($i2 < $c2)
{
if($a2[$i2]->order == $curOrder)
{
//Do what I need to do
break;
}
elseif($a2[$i2]->order > $curOrder)
{
break;
}
$i1++;
}
}
Basically you need to sort each array and find the maxorder, then you loop over the order index and print the items with the given order. This is O(N Log(N)) because of the sorting where N = max number of elements
Here is some pseudo code
sort each array (in php use usort) - O(N log(N))
find maxorder (iterate over each) - O(N)
create an array each index
get the length of each index and store
$a1 = usort($people, function(){})
$a2 = usort($places, function(){})
$a3 = usort($things, function(){})
$c1 = count($a1)
$c2 = count($c2)
$c3 = count($c3)
$i1 = 0
$i2 = 0
$i3 = 0
// itertor over order
for ($curOrder ... $maxorder) {
// while $a1 is on current order and its index is in bound
while ($i1 < $c1 && $a1[$i1]->order == $curOrder) {
echo $a1[$i1]->value;
$i1++;
}
while ($i2 < $c2 && $a2->order == $curOrder) {
echo $a2[$i2]->value;
$i2++;
}
while ($i3 < $c3 && $a3->order == $curOrder) {
echo $a3[$i3]->value;
$i3++;
}
}
If you reindex each array by the object's order value, then you can retrieve an object with a given order in constant time. The code retrieves all related objects in O(n) because you're looking at each element a constant number of times (notice the nested loops have been removed).
$peopleByOrder = array();
$sandwichesByOrder = array();
$restaurantsByOrder = array();
$uniqueOrderKeys = array();
foreach($people as $person) {
$peopleByOrder[$person->order] = $person;
$uniqueOrderKeys[$person->order] = 1;
}
// same for $sandwichesByOrder and $restaurantsByOrder
foreach(array_keys($uniqueOrderKeys) as $oderKey) {
if(isset($peopleByOrder[$orderKey])) {
$person = $peopleByOrder[$orderKey];
}
else if(isset($sandwichesByOrder[$orderKey])) {
$sandwich = $sandwichesByOrder[$orderKey];
}
else if(isset($restaurantsByOrder[$orderKey])) {
$restaurant = $restaurantsByOrder[$orderKey];
}
}
Related
I have for loop in which I have to check that the array that I am retriving should not empty. And if empty then don't display that field.
$checkboxes = array();
$text = array();
$Enhanced = array();
$Search = array();
$Landing = array();
$spotlights="";
for ($i = 1; $i <= 20; $i++) {
$checkboxes[$i] = $_POST[$i];
$text[$i] = $_POST[$i.'t'];
}
for ($p = 1; $p <= 20; $p++) {
$checkboxes[$p] = $_POST[$p];
$Enhanced[$p] = $_POST['Enhanced'.$p];
}
for ($q = 1; $q <= 20; $q++) {
$checkboxes[$q] = $_POST[$q];
$Search[$q] = $_POST['Search'.$q];
}
for ($r = 1; $r <= 20; $r++) {
$checkboxes[$r] = $_POST[$r];
$Landing[$r] = $_POST['Landing'.$r];
}
for ($j = 1; $j <= 20; $j++) {
if($checkboxes[$j]!="")
{
$spotlights=$spotlights."<strong>".$checkboxes[$j]."</strong><br>".$Enhanced[$j]."<br>".$Search[$j]."<br>".$Landing[$j]."<br>".$text[$j]."<br><br>";
}
}
echo $spotlights;
In above code, $Enhanced[$j], $Search[$j], $Landing[$j] may or may not be empty as these are checkboxes. If any of them is empty i don't want to print that. In above case if any of three field empty then it display <br/> which i don't want.
If I check them one by one or combination of them then my code will be longer.
How do I check in smarter way? How should I write the line of $spotlights=... so that it will display only non empty variables($Enhanced[$j], $Search[$j], $Landing[$j])?
I have tried bolow which is not working.
using functions:
for ($j = 1; $j <= 20; $j++) {
if($checkboxes[$j]!="")
{
$spotlights=$spotlights."<strong>".$checkboxes[$j]."</strong>".enhanced($j).search($j).landing($j)."<br>".$text[$j]."<br><br>";
}
}
function enhanced($j) {
if($Enhanced[$j]!="")
{
return "<br/>".$Enhanced[$j];
}
}
function search($j) {
if($Search[$j]!="")
{
return "<br/>".$Search[$j];
}
}
function landing($j) {
if($Landing[$j]!="")
{
return "<br/>".$Landing[$j];
}
}
above code not displaying values of $Enhanced[$j], $Search[$j], $Landing[$j]
checking values independently
for ($j = 1; $j <= 20; $j++) {
if($checkboxes[$j]!="")
{
$spotlights .= $spotlights."<strong>".$checkboxes[$j]."</strong>";
if($Enhanced[$j]!="")
{
$spotlights .= "<br>".$Enhanced[$j];
}
if($Search[$j]!="")
{
$spotlights .= "<br>".$Search[$j];
}
if($Landing[$j]!="")
{
$spotlights .= "<br>".$Landing[$j];
}
$spotlights .= "<br>".$text[$j]."<br><br>";
}
values are getting repeated by using above code.
Use array_filter.
Something like that:
$checkboxes = array_filter($checkboxes);
foreach($checkboxes as $checkbox)
{
$j = array_search($checkbox, $checkboxes)
$spotlights=$spotlights."<strong>".$checkboxes[$j]."</strong><br>".$Enhanced[$j]."<br>".$Search[$j]."<br>".$Landing[$j]."<br>".$text[$j]."<br><br>";
echo $spotlights;
}
array_filter will remove all NULL, false or '' from array, but will keep the position, so if you have in checkbox[3] something different, in checkboxes after array_filter will be on position 3. doesn't matter if on position 2 was NULL.
I don't think checking them individually will be a lot of trouble, as there are only three of them, but if you want to keep it one line, the line where you define $spotlights with this:
$spotlights=$spotlights."<strong>".$checkboxes[$j]."</strong>"
.($Enhanced[$j] != "" ? "<br>".$Enhanced[$j] : "")
.($Search[$j] != "" ? "<br>".$Search[$j] : "")
.($Landing[$j] != "" ? "<br>".$Landing[$j] : "")
."<br>".$text[$j]."<br><br>";
Hope this helped.
I have an issue to deal with here (a logical error in my code 99%). I just can't seem to find the way to fix it, but I bet one of you will find the problem in no time!
I have to create a function which sorts array passed to it in asc or desc order, but can't use any array sorting functions !
I've been struggling with loops until now and I finally want to ask help from other devs ( you ).
Currently only code for ascending is worked on, descending will be no problem I assume once I do this one. It kinda of does sort values up to some point, but then stops ( it stops if the next smallest value is at the end of the passed array ). What could I do to prevent this and make it sort the whole array and it's elements?
Here is the code so far.
<?php
function order_array($array,$mode = 'ascending') {
$length = count($array);
if($mode == 'descending') {
return $array;
} else {
$sorted_array = array();
$used_indexes = array();
for($i = 0; $i < $length; $i++) {
$smallest = true;
echo $array[$i] . '<br/>';
for($y = 0; $y < $length; $y++) {
//echo $array[$i] . ' > ' . $array[$y] . '<br/>';
// if at ANY time during checking element vs other ones in his array, he is BIGGER than that element
// set smallest to false
if(!in_array($y,$used_indexes)) {
if($array[$i] > $array[$y]) {
$smallest = false;
break;
}
}
}
if($smallest) {
$sorted_array[] = $array[$i];
$used_indexes[] = $i;
}
}
return $sorted_array;
}
}
$array_to_sort = array(1, 3, 100, 99, 33, 20);
$sorted_array = order_array($array_to_sort);
print_r($sorted_array);
?>
I've solved the issue myself by doing it completely different. Now it sorts correctly all the elements of the passed in array. The logical issue I had was of using for() loop. The for() loop ran only a set ( length of passed array ) number of times, while we need it to loop more than that, because we will need to loop all the way untill we have a new sorted array in ascending order. Here is the code that will work
function order_array($array,$mode = 'ascending') {
if($mode == 'descending') {
// for() wont work here, since it will only loop an array length of times, when we would need it
// to loop more than that.
while(count($array)){
$value = MAX($array);
$key = array_search($value, $array);
if ($key !== false) {
unset($array[$key]);
}
$sorted[] = $value;
}
return $sorted;
} else {
// for() wont work here, since it will only loop an array length of times, when we would need it
// to loop more than that.
while(count($array)){
$value = MIN($array);
$key = array_search($value, $array);
if ($key !== false) {
unset($array[$key]);
}
$sorted[] = $value;
}
return $sorted;
}
}
function order_array($array,$mode = 'ascending') {
$length = count($array);
$sorted_array = array();
$used_indexes = array();
for($i = 0; $i < $length; $i++) {
$smallest = true;
echo $array[$i] . '<br/>';
for($y = 0; $y < $length; $y++) {
//echo $array[$i] . ' > ' . $array[$y] . '<br/>';
// if at ANY time during checking element vs other ones in his array, he is BIGGER than that element
// set smallest to false
if(!in_array($y,$used_indexes)) {
if($array[$i] > $array[$y]) {
$smallest = false;
break;
}
}
}
if($smallest) {
$sorted_array[] = $array[$i];
$used_indexes[] = $i;
}
if($mode == 'descending') {
return array_reverse($sorted_array);
}
return $sorted_array;
}
}
I'm trying to initialize 3 arrays($tablica1, $tablica2, $tablica3) such that $tablica3 consists of odd numbers and $tablica2 consists of even ones. Finally, I want to have 3 arrays to echo them on the output later. Should I change my way of dealing with this? (It doesn't work). Thanks for support.
$tablica1;
$tablica2;
$tablica3;
for ($i = 0; $i < 50; $i++) {
$j = rand(0, 1000);
$tablica1[$i] = $j;
if ($i % 2 == 0) {
array_push($tablica2, $j);
} else {
array_push($tablica3, $j);
}
}
$tablica1 = array();
$tablica2 = array();
$tablica3 = array();
for ($i=0;$i<50;$i++) {
$j=rand(0,1000);
$tablica1[$i]=$j;
if ($j%2) {
array_push($tablica3,$j);
} else {
array_push($tablica2,$j);
}
}
I am trying to find duplicated values/string in an array using for loop
<?php
$b=array('a','b','c','a','b');
$c=count($b);
$d=array();
for($i=0;$i<=($c-1);$i++)
{
for($j=1;$j<=($c-1);$j++)
{
if($b[$i]!=$b[$j])
{
$flag=1;
}
}
if($flag==1)
{
$d[$i]=$b[$i];
}
}
print_R($d);
?>
where is my mistake? I have used array $d to display non duplicate values.....
NOTE: I need to try this only with for loop - I know how to do it using array functions.
You should reverse your test, because there are almost always values, which are different from the one you're testing. And you must reset your $flag before the inner loop, otherwise it will always be true.
When you want to find unique values, you can just test against $d only. If the value is already in $d, skip it.
$c1 = count($b);
for ($i = 0; $i < $c1; $i++) {
$dup = 0;
$c2 = count($d);
for ($j = 0; $j < $c2; $j++) {
if ($b[$i] == $d[$j])
$dup = 1;
}
if (!$dup)
$d[] = $b[$i];
}
print_r($d);
If you want to find values, which don't have duplicates instead
for ($i = 0; $i < $c; $i++) {
$dup = 0;
for ($j = 0; $j < $c; $j++) {
if ($i != $j && $b[$i] == $b[$j])
$dup = 1;
}
if (!$dup)
$d[] = $b[$i];
}
function has_dupes($array){
$dupe = array();
foreach($array as $val){
if(++$dupe[$val] > 1)
return true;
}
return false;
}
could do something like this.. this would check for dupes, then u can print the uniques
Why are you making a simple task complex .. simply
$b = array('a','b','c','a','b');
var_dump(customCount($b));
Output
array (size=3)
'a' => int 2 //duplicate
'b' => int 2 //duplicate
'c' => int 1
Function Used
function customCount($array) {
$temp = array();
foreach ( $array as $v ) {
isset($temp[$v]) or $temp[$v] = 0;
$temp[$v] ++;
}
return $temp ;
}
I need some help, even though I think I'm checking for the length of the array and I should be breaking out of the loop, I still get warnings on my [else if ($value....] line. So either I'm missing something crucial or I've been staring at this code segment too long and its obvious. Any insight would be appreciated.
$count = count($filter); //Filter is an array
if ($count > 1 ){
//Compare values and generate a range to choose from
$i = 1;
foreach($filter as $value){
//Break the loop if at the end of the array
if ($i >= $count){
//throw new exception($i .' '.$count);
break;
}
//if the value is smaller then the next procceding value, because they are already in order of presidence,
//add it to our range of potentials.
else if($value < $filter[$i]->value){
array_push($range, key($filter));
}
$i++;
}
}else {
return false;
}
I suspect that there are gaps in your array. Try this:
$filter = array_values($filter); // this will remove any gaps in the array
$count = count($filter);
if ($count <= 1)
return false;
for ($i = 0; $i < $count; $i++)
{
if ($i != $count-1 && $filter[$i]->value < $filter[$i+1]->value)
array_push($range, key($filter));
}
Your array might have non-numeric keys. Then try this:
foreach($filter as $key=>$value)
{
// test for $filter[$key];
}
Or your $filter array doesn't hold objects, then you can't use the -> in
$filter[$key]->value
try this code.... no need of checking count..
$range = array();
$i = 1;
foreach($filter as $value)
{
if(isset($filter[$i]) && $value < $filter[$i]->value)
{
array_push($range, key($filter));
$i++;
}
else
{
break;
}
}