I am having an hard time trying to create an associative array from a collection in Laravel. The array should then be used for case checking.
I get my collection like this:
$collected_items = $user->collected_items()->where('model_id', '=', $model_id)->get();
I need to extract only some relevant data from this collection like 'color_id'
I need to check the color_id because I should run different code if the color_id = 0, 1 or 2
Since I don't want to do a DB query for every case I thought I'd better eager load the data and then put it in an associative array;
However for the life of me I can't create this array
I tried:
$array_of_colors = []
foreach ($collected_items as $i) {
if ($i['color_id'] == 0) {
$array_of_colors += ['black' => $i->model_color_id];
}
if ($i['color_id'] == 1) {
$array_of_colors += ['colored' => $i->model_color_id];
}
if ($i['color_id'] == 2) {
$array_of_colors += ['white' => $i->model_color_id];
}
}
Then I would use the $array_of_colors to check if I have a case of black then do something, is white something else etc etc.
Instead of doing it that way I highly recommend using the Collection functions available in Laravel. In particular I think filter() will work well for you.
https://laravel.com/docs/5.4/collections#method-filter
Something like this:
$black_items = $collected_items->filter(function ($value, $key) {
return $value->model_color_id == 1;
});
$array_of_colors = []
foreach ($collected_items as $i) {
if ($i['color_id'] == 0) {
$array_of_colors[] = ['black' => $i->model_color_id];
}
if ($i['color_id'] == 1) {
$array_of_colors[] = ['colored' => $i->model_color_id];
}
if ($i['color_id'] == 2) {
$array_of_colors[] = ['white' => $i->model_color_id];
}
}
Related
i wondering how i can make it simpler...
the thing is
if($results['experience'] == 0) { loadViev('experience',$experience, $careerGoals,$mainSectionLines); }
if($results['Education'] == 0) { loadViev('Education',$graduate,$careerGoals,$mainSectionLines); }
if($results['Extra'] == 0) { loadViev('Extra',$extra,$careerGoals,$mainSectionLines); }
if($results['Licence'] == 0) { loadViev('Licence',$licence,$careerGoals,$mainSectionLines); }
if($results['Cert'] == 0) { loadViev('Certyfikaty',$cert,$careerGoals,$mainSectionLines); }
if($results['conferences'] == 0){ loadViev('Conferences',$conferences,$careerGoals,$mainSectionLines); }
if($results['Courses'] == 0) { loadViev('Courses',$Courses,$careerGoals,$mainSectionLines); }
if($results['Hobbys'] == 0) { loadViev('Hobby',$hobby,$careerGoals,$mainSectionLines); }
As you can see, if some "name" == 0 function will run, there is for now around 14 combination, i know there is possible to do it faster than copy and paste whole code 14 times...
result code:
$results =[];
foreach ($userChoice as $key => $value) {
$setVal = $value['key'];
$results[$setVal] = $value['order'];
}
Result only grab name of a section and order nr.
'$userChoice' is just a array with data
Do anybody have a idea how i can do it?
Also the thing is result collect all the section data (14 section) where as you can see i need only selected 8.
The only difference is the word being loaded and the name of the variable. The word remains the same, but the variable is lowercase.
As such, all you would need to do is loadViev the $setVal name (the word itself) as the first argument, and $$setval as the second. This executes the word as a variable, making use of variable variables.
Unfortunately you can't (easily) use something like strtolower() on a variable variable directly, so you'll have to convert these to lowercase independently first.
This can be seen in the following:
$results =[];
foreach ($userChoice as $key => $value) {
$setVal = $value['key'];
$results[$setVal] = $value['order'];
if ($value['order'] == 0) {
$lower = strtolower($setVal);
loadViev($setVal, $$lower, $careerGoals, $mainSectionLines);
}
}
How about creating a structure holding relevant values and iterating over it?
$mapping = [
['key' => 'experience', 'view' => 'experience','data' => $experience],
['key' => 'Education', 'view' => 'Education','data' => $graduate],
['key' => 'Extra', 'view' => 'Extra','data' => $extra],
...
...
];
foreach ($mapping as $m)
{
if ($results[$m['key']]==0)
{
loadViev($m['view'], $m['data'], $careerGoals,$mainSectionLines);
break;
}
}
if you can make your key/variable names consistent, you could simplify the code even further. E.g.
$validKeys = ['experience', 'education', ... ];
foreach($validKeys as $k)
{
if($results[$k] == 0)
{
loadviev($k, $$k, $careerGoals,$mainSectionLines)
}
}
As there is no iterator in PHP, the only way to loop through an array without getting the length of the array is to use foreach loop.
Let say I have the following loop:
foreach ($testing_array as $testing_entry) {
$result = my_testing_api_call($testing_entry);
if ($result == 'server dead')
break;
else if ($result == 'done') {
// do something to handle success code
continue;
}
else {
sleep(5);
// I want to retry my_testing_api_call with current $testing entry, but don't know what to write
}
}
One way to do that is to use for loop instead.
for ( $i=0; $i < count($testing_array); $i++ ) {
$result = my_testing_api_call($testing_entry[$i]);
if ($result == 'server dead')
break;
else if ($result == 'done') {
// do something to handle success code
continue;
}
else {
sleep(5);
$i--; //so it will repeat the current iteration.
}
}
The problem is that the $testing_array is not originally using number as index, so I have to do some data massage to use a for loop. Is there a way I can repeat a specific iteration in a foreach loop?
Perhaps a do-while will work for you.
Untested Code:
foreach ($testing_array as $testing_entry) {
do {
$result = my_testing_api_call($testing_entry);
if ($result == 'server dead') {
break 2; // break both loops
} elseif ($result == 'done') {
// do something to handle success code
} else {
sleep(5);
// I want to retry my_testing_api_call with current $testing entry, but don't know what to write
}
} while ($result !== 'done');
}
Or a single loop structure that destroys the input array as it iterates.
Untested Code:
$result = '';
while ($testing_array && $result !== 'server dead') {
$result = my_testing_api_call(current($testing_array));
if ($result == 'done') {
// do something to handle success code
array_shift($testing_array);
} elseif ($result !== 'server dead') {
sleep(5); // I want to retry my_testing_api_call with current $testing entry, but don't know what to write
}
}
Or you can use your for loop by indexing $test_array with array_values() if you don't need the keys in your // do something.
$testing_array = array_values($testing_array);
for ($i=0, $count=count($testing_array); $i < $count; ++$i) {
$result = my_testing_api_call($testing_entry[$i]);
if ($result == 'server dead') {
break;
} else if ($result == 'done') {
// do something to handle success code
} else {
sleep(5);
--$i; //so it will repeat the current iteration.
}
}
If you do need the keys down script, but you want to use for, you could store an indexed array of keys which would allow you to use $i to access the keys and maintain data synchronicity.
My final suggestion:
Use while (key($testing_array) !== null) {...} to move the pointer without destroying elements.
Code: (Demo)
$array1 = [
"one" => 1,
"two" => 2,
"three" => 3,
"four" => 4
];
while (key($array1)!==null) { // check if the internal pointer points beyond the end of the elements list or the array is empty
$current = current($array1);
$key = key($array1);
echo "$key => $current\n"; // display current key value pair
if ($current < 3) { // an arbitrary condition
echo "\t";
$array1[$key] = ++$current; // increment the current value
} else { // current value is satisfactory
echo "\t(advance pointer)\n";
next($array1); // move pointer
}
}
Output:
one => 1
one => 2
one => 3
(advance pointer)
two => 2
two => 3
(advance pointer)
three => 3
(advance pointer)
four => 4
(advance pointer)
You are trying to handle two different things in your loop, that makes it hard to write clean control flow. You could separate the retry-logic from the result handling:
function call_api_with_retry($entry) {
do {
if (is_defined($result)) sleep(5);
$result = my_testing_api_call($entry);
} while ($result != 'done' && $result != 'server dead');
return $result;
}
foreach ($testing_array as $testing_entry) {
$result = call_api_with_retry($testing_entry);
if ($result == 'server dead')
break;
else if ($result == 'done') {
// do something to handle success code
continue;
}
}
(there might be syntax errors, it's been a while since I wrote PHP code)
To repeat a single specific iteration you need to add a control mechanism, it is not an intended behavior after all.
There are many suggestions here, all of them are kinda over-engineered.
PHP is a high level derivate of C and both languages have the 'goto' operator, it has a bad reputation because people have historically used it too much.
In the end a foreach/while loop is internally nothing else than a 'goto' operation.
Here is the code:
foreach ($array as $key => $value)
{
restart:
if ($value === 12345) goto restart;
}
That's how this should be done just keep in mind that this can cause an endless loop, like in the example.
Look at the next complicated version without goto:
foreach ($array as $key => $value) while(1)
{
if ($value === 12345) continue;
break;
}
This is essentially the same as the goto, just with more code.
If you'd want to "break" or "continue" the foreach loop you'd write "break 2" or "continue 2"
I have an associative array like this:
9584=>string
5324=>string
6543=>string
The key is always a number but I assign it dynamically so I don't know the numbers and probably they are not consecutive.
I need to know if the string is the same in ALL of the occurrence in the array.
If you can help me thank you... and sorry for my horrible English
Let me count the ways... There are bound to be more:
if(count(array_flip($array)) === 1) { }
if(count(array_unique($array)) === 1) { }
if(count(array_count_values($array)) === 1) { }
Read the first value and browse your array until you find a different one.
<?php
function allTheSame($array)
{
if (count($array) != 0)
{
$first = reset($array);
foreach($array => $v)
{
if ($v !== $first)
{
return false;
}
}
}
return true;
}
I have a rather ugly query, and the results from the query are then post-processed using php which turns each row into it's own multidimensional array.
I want to refactor the query but need to make sure I do not change what it returns in any way.
So What I want to do is copy the original query and call that, store the results.
then run the function again with my new query.
Loop over the two arrays of results and compare them for any differences what so ever (keys, values, missing entries, type differences etc).
What is the easiest way to do this?
Essentially I know how to call the two queries etc,
I guess my real question is, at the end once I have my two arrays of the results how do I go through and compare them.
What I would love to end up with is a side by side "print_r" type output with a red line or similar going across highlighting any differences.
First of all, you can use array_uintersect_assoc() like this.
// First get intersecting values
$intersect = array_uintersect_assoc($expected, $results, "checkStructure");
print_r($intersect);
//Then print results that are in intersecting set (e.g. structure of $expected, value of $results
print_r(array_uintersect_assoc($results, $intersect, "checkStructure"));
function checkStructure($x, $y) {
if (!is_array($x) && !is_array($y)) {
return 0;
}
if (is_array($x) && is_array($y)) {
if (count($x) == count($y)) {
foreach ($x as $key => $value) {
if(array_key_exists($key,$y)) {
$x = checkStructure($value, $y[$key]);
if ($x != 0) return -1;
} else {
return -1;
}
}
}
} else {
return -1;
}
return 0;
}
If still not, take help of array_diff()
and array_diff_assoc(). Or try following code.
function multidimensional_array_diff($a1,$a2)
{
$r = array();
foreach ($a2 as $key => $second)
{
foreach ($a1 as $key => $first)
{
if (isset($a2[$key]))
{
foreach ($first as $first_value)
{
foreach ($second as $second_value)
{
if ($first_value == $second_value)
{
$true = true;
break;
}
}
if (!isset($true))
{
$r[$key][] = $first_value;
}
unset($true);
}
}
else
{
$r[$key] = $first;
}
}
}
return $r;
}
Why don't you just make a VIEW that turns an ugly query into something you can just SELECT against? What you're talking about is making a materialized view, something that MySQL doesn't handle as well as other database platforms.
Why not write the results of each query out to a text files then compare the two text files with the diff command?
How can I count the number of items with the same folder_id# ?
Here's my list of items:
item_id=1, folder_id=1
item_id=2, folder_id=1
item_id=3, folder_id=2
item_id=4, folder_id=3
Here's my UPDATED code:
foreach($items as $item)
{
if(????) //count of $item->folder_id > 1
{
//do something to $item->folder_id=1/$item->item_id=1
}
elseif(????) // cases where $item->item_id != $item->folder_id
{
//do something else to $item->folder_id=1/$item->item_id=2
}
else
{
//do something else to $item->folder_id=2/$item->item_id=3 and folder_id=3/item_id=4
}
}
I'm interested in code that can tell me that the count for folder_id=1 is 2, the count for folder_id=2 is 1, and the count for folder_id=3 is also 1.
UPDATE: I've changed the code above to now include an elseif() because it didn't quite ask all the things I was interested in. Besides counting the # of each folder_id, I'm also interested in distinguishing cases where folder_id != item_id. This would put item_id=1, item_id=2, item_id=3/4 in their own conditional clauses and wouldn't lump item_id=1 and item_id=2 as before.
Any assistance would be greatly appreciated, thank you,
If you had an array of folder_ids, you could use array_count_values to provide exactly the result you need. So let's make an array like that out of an array of objects using array_map:
$callback = function($item) { return $item->folder_id; };
$result = array_count_values(array_map($callback, $items));
This will end up with $result being
array(
1 => 2,
2 => 1,
3 => 1,
);
You can also write the callback inline for an one-liner, or if you are on PHP < 5.3 you can write it as a free function or alternatively using create_function.
See it in action (version for PHP < 5.3).
Update: follow up
Given $results from above, your loop would be:
foreach($results as $folder_id => $count) {
if($count > 1) {
// There were $count items with folder_id == $folder_id
}
// else blah blah
}
$totals = array();
foreach($items as $item) {
$totals[$item->folder_id]++;
}
function count_items(Array $items, $folder_id) {
return count(array_filter($items,
function($item) use($folder_id) {
return $item->folder_id === $folder_id;
}
));
}
I think this is what you are looking for.
function folder_count($items, $num)
{
$cnt = 0;
foreach($items as $item)
{
if($item->folder_id > $num)
{
$cnt++;
}
}
return $cnt;
}
foreach ($items as $item)
{
if (folder_count($items, 1))
{
//do something to $item->folder_id=1/$item->item_id=1, item_id=2
}
else
{
//do something else to $item->folder_id=2/$item->item_id=3 and folder_id=3/item_id=4
}
}