How to put value on laravel collection? - php

How to put value on first element in laravel collection ? Something like that $collection->put('foo', 1) but adding value to the first element.
Collection {#376
#items: array:1 [
0 => array:9 [
"id" => 83
"status" => "offline"
"created_date" => "Oct 31, 2018"
// add foo => 1 here
]
]
}

I suspect there's a cleaner way to do this, but this is the best I could come up with at the moment. You could also use map or transform with a comparison run on the key value that gets sent to their closures, but that would end up cycling through all elements of the array despite you knowing the specific one you want to target.
$collection = collect([
[
'id' => 83,
'status' => 'offline',
'created_date' => 'Oct 31, 2018'
]
]);
$firstKey = $collection->keys()->first(); //This avoids the unreliable assumption that your index is necessarily numeric.
$firstElement = $collection->first();
$modifiedElement = array_merge($firstElement, ['foo1' => 1]);
$collection->put($firstKey, $modifiedElement);

use this
$data = Model::all();
$data[0]->foo = 'your data here';

Related

Underfined key 1 in an array of 2 keys

I've the following issue. I've an explode() and as return I've 2 keys. But it still give me an exception of can't find array key 1. But when I debug on key 1 it shows me a correct result. How can this be?
[$first, $last] = explode('-', $hours[$key]['time'], 2);
dd(trim($last));
$days[] = [
'id' => $hours[$key]['id'],
'day' => $key,
'begin_time' => trim($first),
'end_time' => trim($last),
'free' => false,
];
Array
"Monday" => array:3 [▶
"time" => "9:00 - 14:45"
"id" => "1098"
"week" => "1"
]
Input Value
"9:00 - 14:45"
the value of $hours[$key]['time'] may not contain "-" so its not getting the value for array [$first, $last]
if you put dd() statement then its brack your loop so try print() or echo instead of dd() or dd your whole $hours array before explode
dd($hours).

Compare arays and exclude element form one if it has duplicates in others

I need to compare arrays, if element from first or second array has duplicates in another one I need to exclude it. I know it sound simply and I'm sure it is but i cant handle with that problem :(
So i have first array like this:
Array:3 [
6 => blog/something
4 => blog/somethingElse
5 => blog/else
]
Second array almost identical:
Array:3 [
1 => /blog
2 => /comments
3 => /posts
]
And the last array:
(integer on the left is id of elements in second array, in this example
comments and posts)
Array:2 [
0 => array:2 [
'page_id' => 2
'value' => noindex
]
1 => array:2 [
'page_id' => 3
'value' => noindex
]
]
So if I have element in array first or second which exist in array thrid too AND have value = noindex i need to exclude it.
I have tried do this by foreach recursive, by array_walk_recursive but I still can't get satisfied result
First get all the indices you need to exclude and then exclude them:
$excludeIndices = array_column(array_filter($array3, function ($entry) {
return $entry['value'] === 'noindex';
}), 'page_id');
$keepArray1 = array_diff_key($array1, array_flip($excludeIndices));
$keepArray2 = array_diff_key($array2, array_flip($excludeIndices));
Sandbox
You can filter using the first two arrays directly.
$result = array_filter($last, function($item) use ($first, $second) {
return !($item['value'] == 'noindex' &&
(isset($first[$item['page_id']]) || isset($second[$item['page_id']]))
);
});

Why is array_merge_recursive not recursive?

I recently found a bug in my application caused by unexpected behaviour of array_merge_recursive. Let's take a look at this simple example:
$array1 = [
1 => [
1 => 100,
2 => 200,
],
2 => [
3 => 1000,
],
3 => [
1 => 500
]
];
$array2 = [
3 => [
1 => 500
]
];
array_merge_recursive($array1, $array2);
//returns: array:4 [ 0 => //...
I expected to get an array with 3 elements: keys 1, 2, and 3. However, the function returns an array with keys 0, 1, 2 and 3. So 4 elements, while I expected only 3. When I replace the numbers by their alphabetical equivalents (a, b, c) it returns an array with only 3 elements: a, b and c.
$array1 = [
'a' => [
1 => 100,
2 => 200,
],
'b' => [
3 => 1000,
],
'c' => [
1 => 500
]
];
$array2 = [
'c' => [
1 => 500
]
];
array_merge_recursive($array1, $array2);
//returns: array:3 [ 'a' => //...
This is (to me at least) unexpected behaviour, but at least it's documented:
http://php.net/manual/en/function.array-merge-recursive.php
If the input arrays have the same string keys, then the values for
these keys are merged together into an array, and this is done
recursively, so that if one of the values is an array itself, the
function will merge it with a corresponding entry in another array
too. If, however, the arrays have the same numeric key, the later
value will not overwrite the original value, but will be appended.
The documentation isn't very clear about what 'appended' means. It turns out that elements of $array1 with a numeric key will be treated as indexed elements, so they'll lose there current key: the returned array starts with 0. This will lead to strange outcome when using both numeric and string keys in an array, but let's not blame PHP if you're using a bad practice like that. In my case, the problem was solved by using array_replace_recursive instead, which did the expected trick. ('replace' in that function means replace if exist, append otherwise; naming functions is hard!)
Question 1: recursive or not?
But that's not were this question ends. I thought array_*_resursive would be a recursive function:
Recursion is a kind of function call in which a function calls itself.
Such functions are also called recursive functions. Structural
recursion is a method of problem solving where the solution to a
problem depends on solutions to smaller instances of the same problem.
It turns out it isn't. While $array1 and $array2 are associative arrays, both $array1['c'] and $array2['c'] from the example above are indexed arrays with one element: [1 => 500]. Let's merge them:
array_merge_recursive($array1['c'], $array2['c']);
//output: array:2 [0 => 500, 1 => 500]
This is expected output, because both arrays have a numeric key (1), so the second will be appended to the first. The new array starts with key 0. But let's get back to the very first example:
array_merge_recursive($array1, $array2);
// output:
// array:3 [
// "a" => array:2 [
// 1 => 100
// 2 => 200
// ]
// "b" => array:1 [
// 3 => 1000
// ]
// "c" => array:2 [
// 1 => 500 //<-- why not 0 => 500?
// 2 => 500
// ]
//]
$array2['c'][1] is appended to $array1['c'] but it has keys 1 and 2. Not 0 and 1 in the previous example. The main array and it's sub-arrays are treated differently when handling integer keys.
Question 2: String or integer key makes a big difference.
While writing this question, I found something else. It's getting more confusing when replacing the numeric key with a string key in a sub-array:
$array1 = [
'c' => [
'a' => 500
]
];
$array2 = [
'c' => [
'a' => 500
]
];
array_merge_recursive($array1, $array2);
// output:
// array:1 [
// "c" => array:1 [
// "a" => array:2 [
// 0 => 500
// 1 => 500
// ]
// ]
//]
So using a string key will cast (int) 500 into array(500), while using a integer key won't.
Can someone explain this behaviour?
If we take a step back and observe how array_merge*() functions behave with only one array then we get a glimpse into how it treats associative and indexed arrays differently:
$array1 = [
'k' => [
1 => 100,
2 => 200,
],
2 => [
3 => 1000,
],
'f' => 'gf',
3 => [
1 => 500
],
'99' => 'hi',
5 => 'g'
];
var_dump( array_merge_recursive( $array1 ) );
Output:
array(6) {
["k"]=>
array(2) {
[1]=>
int(100)
[2]=>
int(200)
}
[0]=>
array(1) {
[3]=>
int(1000)
}
["f"]=>
string(2) "gf"
[1]=>
array(1) {
[1]=>
int(500)
}
[2]=>
string(2) "hi"
[3]=>
string(1) "g"
}
As you can see, it took all numeric keys and ignored their actual value and gave them back to you in the sequence in which they were encountered. I would imagine that the function does this on purpose to maintain sanity (or efficiency) within the underlying C code.
Back to your two array example, it took the values of $array1, ordered them, and then appended $array2.
Whether or not this behavior is sane is a totally separate discussion...
You should read the link you provided it states (emphasis mine):
If the input arrays have the same string keys, then the values for these keys are merged together into an array, and this is done recursively, so that if one of the values is an array itself, the function will merge it with a corresponding entry in another array too. If, however, the arrays have the same numeric key, the later value will not overwrite the original value, but will be appended.

Make multiple PHP arrays out of a single array and store those new arrays into new single array

this might be a bit of a generic title, but I will try to explain my problem the best way I can.
So I've got this type of associative array:
Array
(
[ICO_0] => checked
[Investment_0] => checked
[Investment_1] => checked
[Marketing_1] => checked
)
What I would like to do is to divide it into multiple arrays based on numbers that are attached to the end of the key ( 0, 1 ... ). Basically I'd like to get a new array to look like this:
Array(
Array(
[ICO_0] => checked
[Investment_0] => checked
[Token Sale_0] => checked
),
Array(
[Investment_1] => checked
[Marketing_1] => checked
)
)
I've tried approaching this issue with array_chunk but couldn't get it to work.
I'll need this output since I want to sort those nested arrays based on items that they're holding, starting from the highest number of items.
Thanks!
You can use several different methods to accomplish this. One method is to loop through and explode the key name if you know there will always be an underscore, grab the last number, and use that as your index:
$results = [
"ICO_0" => "checked",
"Investment_0" => "checked",
"Investment_1" => "checked",
"Marketing_1" => "checked",
"Investment_2" => "checked",
"Marketing_2" => "checked"
];
foreach($results as $key => $value){
$ex = explode('_', $key);
$new_result[end($ex)][$key] = $value;
}
Which for me returns the following:
array:3 [▼
0 => array:2 [▼
"ICO_0" => "checked"
"Investment_0" => "checked"
]
1 => array:2 [▼
"Investment_1" => "checked"
"Marketing_1" => "checked"
]
2 => array:2 [▼
"Investment_2" => "checked"
"Marketing_2" => "checked"
]
]

php replace ids in array

I got the following array:
"task" : {
"author_id" : 150,
"created_at" : somedate,
"status_id" : 2,
"assignee_id" : 100,
"updated_at" : somedate_too
and I got 2 more associative arrays where I store names for IDs in the following way:
"100" => Mike,
"150" => Bob //etc..., the same for statuses
I need to check for the IDs in the first array and replace numbers with names for the corresponding arrays in the most effective way. I tried the following:
if(isset(task['status_id'])){$row = array_merge($row, [$status_ids[
task['status_id']]]);}else{$row = array_merge($row, '');}
if(isset(task['author_id'])){row = array_merge($row, [$users[// note the different array here
task['author_id']]]);}else{$row = array_merge($row, '');}
if(isset(task['assignee_id'])){$row = array_merge($row, [$users[
task['assignee_id']]]);}else{$row = array_merge($row, '');}
In my resulting array ($row) I cannot miss the index and replace it with another value. If there is no value in the first array, I need to insert an empty string to get the following, for example:
['in progress', '', 'Mike']
if there is no author_id in the first array. I believe there should be a better way to do it with foreach loop, but I cant find out how because for different fields I get the data from different arrays. I dont think a separate if clause for every field is the most suitable here.
Any help would be welcome. Thank You.
You could map your special keys to their array counterparts using references and use that mapping when populating $row, like this:
$users = [
"100" => "Mike",
"150" => "Bob",
];
$status_ids = [
1 => "Foo",
2 => "Bar",
];
// Define output format and array mapping
$mapping = [
"author_id" => &$users, // Mapped to $users array
"created_at" => null, // Not mapped, keep $task value
"status_id" => &$status_ids,
"assignee_id" => &$users,
"updated_at" => null,
];
$task = [
"author_id" => 150,
"created_at" => "Some date",
"status_id" => 2,
// "assignee_id" => 99999, // Oops, missing key/value => empty string in $row
"updated_at" => "Some other date",
];
foreach ($mapping as $key => $mappedArray) {
#$row[] = $mappedArray
? $mappedArray[$task[$key]] ?: ''
: $task[$key];
}
print_r($row);
Output:
Array
(
[0] => Bob
[1] => Some date
[2] => Bar
[3] =>
[4] => Some other date
)
It should work (I didn't try it, but it should give you the general idea):
<?php
$fields = array("author_id", "assignee_id", "status_id");
$aliases = array("users", "users", "status_ids");
foreach ($task as $key=>&$value) {
$alias = str_replace($fields, $aliases, ${$key});
if (is_array(${$alias}) {
$value = array_key_exists($value, ${$alias}) ? ${$alias}[$value] : "";
}
}
unset($value);
And then you can fill up your $row as you planned, directly from the $task array.

Categories