I've stumbled upon this function today:
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
];
}
I don't understand this construction:
['status', 'default', 'value' => self::STATUS_ACTIVE]
How's that first two entries have only value, and the third has a key and a value. Is it something that PHP language allows?
This is nothing new. Key is just optional. You can find a similar case in the very first example of the PHP documentation for arrays.
Here it is.
<?php
$fruits = array (
"fruits" => array("a" => "orange", "b" => "banana", "c" => "apple"),
"numbers" => array(1, 2, 3, 4, 5, 6),
"holes" => array("first", 5 => "second", "third")
);
?>
http://php.net/manual/en/function.array.php
Related
I am looking for a way to sort the collection in such a way that name values starting with the alphabet comes at the top and then name values that start with numbers. For example:
$collection = collect([
['name' => 'b', 'symbol' => '#'],
['name' => '2a', 'symbol' => '$'],
['name' => '1', 'symbol' => '#'],
['name' => 'a', 'symbol' => '%']
]);
The above collection should be sorted like this:
[
[
"name" => "a",
"symbol" => "%",
],
[
"name" => "b",
"symbol" => "#",
],
[
"name" => "1",
"symbol" => "#",
],
[
"name" => "2a",
"symbol" => "$",
],
]
But this is what I get when I sort it using sortBy method:
$collection->sortBy('name')->values()->all();
[
[
"name" => "1",
"symbol" => "#",
],
[
"name" => "2a",
"symbol" => "$",
],
[
"name" => "a",
"symbol" => "%",
],
[
"name" => "b",
"symbol" => "#",
],
]
Any idea how to sort this collection so that names starting with letters come first?
You need to define your own custom comparator function to sort these collection objects using sort.
Compare both names by checking they are all alphabets. If both are alphabets, then usual string comparison using strcasecmp shall suffice. If either of them is an alphabet, push them to higher ranks by returning value -1, meaning to be placed above in the sorted order. If both are numerical or alphanumeric, use strcasecmp again.
<?php
$collection = collect([
['name' => 'b', 'symbol' => '#'],
['name' => '2a', 'symbol' => '$'],
['name' => '1', 'symbol' => '#'],
['name' => 'a', 'symbol' => '%']
]);
$collection = $collection->sort(function($a,$b){
$a_is_alphabet = preg_match('/^[a-zA-Z]+$/', $a['name']) === 1;
$b_is_alphabet = preg_match('/^[a-zA-Z]+$/', $b['name']) === 1;
if($a_is_alphabet && $b_is_alphabet){
return strcasecmp($a['name'], $b['name']);
}elseif($a_is_alphabet){
return -1;
}elseif($b_is_alphabet){
return 1;
}
return strcasecmp($a['name'], $b['name']);
});
You want purely alphabetical name values to have top priority, then I assume natural sorting so that, say a2 comes before a10. Just write two rules in a custom callback in a sort() method call.
False evaluations are ordered before true evaluations when sorting ASC, so merely write the $b element before the $a element to sort DESC. To break any ties on the first comparison, call strnatcmp().
Laravel adopted arrow function syntax back in 2019.
Code: (Basic PHP Demo)
$collection->sort(fn($a, $b) =>
(ctype_alpha($b['name']) <=> ctype_alpha($a['name']))
?: strnatcmp($a['name'], $b['name'])
);
If you, more specifically only want to check if the first character is a letter, you can use $a['name'][0] and $b['name'][0]. If the strings might have a multi-byte first character then a regex approach might be best.
I write code with some array that have different structure, but I must extract the data to do something else. How can I manager these array?
The array's structure are as follow:
$a = [
'pos1' => 'somedata',
'pos2' => ['data2', 'data3'],
'pos3' => '';
];
$b = [
[
'pos1' => ['data1', 'data2', ['nest1', 'nest2']],
'pos2' => ['data1', 'data2', 'data3'],
],
['data1', 'data2'],
'data4',
];
The array's Index can be a key or a position, and the value of the corresponding index may be a array with the same structure. More tough problem is that the subarray can be nesting, and the time of the nesting has different length.
Fortunately, every array has it's owe fixed structure.
I want to convert the these array to the format as follow. When the index is a value, change it to the keyword; and if the index is a keyword, nothing changed.
$a = [
'pos1' => 'somedata',
'pos2' => [
'pos2_1' => 'data2',
'pos2_2' => 'data3'
],
'pos3' => '';
];
$b = [
'pos1' => [
'pos1_1' => [
'pos1_1_1' => 'data1',
'pos1_1_2' => 'data2',
'pos1_1_3' => [
'pos1_1_3_1' => 'nest1',
'pos1_1_3_2' => 'nest2',
],
],
'pos1_2' => [
'pos1_2_1' => 'data1',
'pos1_2_2' => 'data2',
'pos1_2_3' => 'data3',
],
],
'pos2' => ['data1', 'data2'],
'pos3' => 'data4',
];
My first solution is for every array, write the function to convert the format(the keyword will specify in function). But it is a huge task and diffcult to manage.
The second solution is write a common function, with two argument: the source array and the configuration that specify the keyword to correspondent value index. For example:
$a = [0, ['pos10' => 1]];
$conf = [
// It means that when the value index is 0, it will change it into 'pos1'
'pos1' => 0,
'pos2' => 1,
];
The common funciton will generate the result of:
$result = [
'pos1' => 0,
'pos2' => ['pos10' => 1],
]
But this solution will lead to a problem: the config is diffcult to understand and design, and other people will spend a lot of time to understand the format after conversion.
Is there are some better solution to manage these array that other people can easy to use these array?
Thanks.
I have an 2 dimensional array with this values :
[
'id' => 12,
'title' => 'the title', //and a few other key => value
],
[
'id' => 13,
'title' => 'the title 13', // and a few other key => value
],...
In the end, I need to have a multidimensional array only with id and title
[ $item['id'] => $item['title'], ...]
Usually, I'm doing a simple foreach to achieve this, but I want to use php function now. I've done this, but is there a proper way to do this?
$list = array_combine(array_column($list_forms, 'id'), array_column($list_forms, 'title'));
With third argumenf of array_column it is:
$list = array_column($list_forms, 'title', 'id');
I want to print all unique Department values from a multidimensional array as a comma-separated string, but not all rows have a Department value.
The boiled down version of my array looks like this:
$employee = [
["employee_id" => 1, "Department" => "Tech"],
["employee_id" => 2, "Department" => "Tech"],
["employee_id" => 3],
["employee_id" => 4, "Department" => "Tech"],
["employee_id" => 5],
["employee_id" => 6, "Department" => "Crm"],
["employee_id" => 7],
["employee_id" => 8, "Department" => "Crm"],
["employee_id" => 9, "Department" => "Crm"],
["employee_id" => 10],
["employee_id" => 11, "Department" => "Crm"],
["employee_id" => 12, "Department" => "Crm"]
];
I tried with:
for ($i=0; $i < count($employee); $i++) {
print_r(array_unique($employee[$i]['Department']));
}
But I generate Warnings when I try to access a non-existent Department value.
Expected output:
Tech,Crm
<?php
echo implode(",",array_unique(array_column($employee,'Department')));
Use array_column to filter values of Department column and use array_unique() to have unique values of Department. Now, just implode() them based on ,.
You can avoid calling array_unique() after array_column() by repeating its second parameter as its third parameter. PHP does no allow duplicate kays on the same level as an array. When a repeated Department is encountered, the old value is replaced with its newer, identical value.
Code: (Demo)
echo implode(',', array_column($employee, 'Department', 'Department'));
// Tech,Crm
PHP re-group array by each column to multiple array without loop
In Laravel DB return, i.e. ->get()->toArray() result is as such:
[
['ts' => 1234, 'a' => 3, 'b' => 2],
['ts' => 1244, 'a' => 2, 'b' => 6],
['ts' => 1254, 'a' => 8, 'b' => 3],
]
Is there any way that I am able to transform the data to as such:
[
['column' => 'a', 'values' => [[1234, 3], [1244, 2], [1254, 8]],
['column' => 'b', 'values' => [[1234, 2], [1244, 6], [1254, 3]],
]
I just wish to know if there's any best / efficient way to render the transformation as described above. Avoid re looping again as data is already available, it can be thought as a data formatting question. Also, I do not wish to use additional array if possible.
Things that I've already looked includes ->get()->map(function()), however this is sequential and I am not able to get values in 2D array as a result.
You'll want to map over your items and return the ts value, as well as the value for each column, respectively:
$items = Model::all();
$result = [
[
'column' => 'a',
'values' => $items->map(function ($item) {
return [$item->ts, $item->a];
})
],
[
'column' => 'b',
'values' => $items->map(function ($item) {
return [$item->ts, $item->b];
})
],
];
If you want to combine the logic for both columns, create a collection of column names, and map over those:
$items = Model::all();
$result = collect(['a', 'b'])->map(function ($column) use ($items) {
$values = $items->map(function ($item) use ($column) {
return [$item->ts, $item->{$column}];
});
return compact('column', 'values');
});