I get PDO rows array which contains the result:
parent_id , item_id
NULL 2
NULL 3
1 5
1 8
I want a new array where parent_id is not NULl
Means
new arr=[5,8]
You need to set new array from exits or to duplicate request with IS NULL condition. With array method, your code will show like this:
$arr = [
[
'parent_id' => null,
'item_id' => 2,
],
[
'parent_id' => null,
'item_id' => 4
],
[
'parent_id' => 2,
'item_id' => 20,
],
];
$new_arr = array_filter($arr,function ($item) {
return !$item['parent_id'];
});
print_r($new_arr);
Related
I have a Laravel collection with record IDs and foreign keys:
{id=1, foreign_id=1},
{id=2, foreign_id=1},
{id=3, foreign_id=2},
{id=4, foreign_id=3},
{id=5, foreign_id=2}
I expect:
{id=2, foreign_id=1},
{id=5, foreign_id=2},
{id=4, foreign_id=3}
I want to search Laravel query builder for unique values for foreign_id if id in collection occurs more than 1 time.
I want then to give latest foreign_id.
Try $collection->unique('foreign_id');
Here I'm giving an example, You can check by yours,
$a = collect([
[
'id' => 1,
'foreign_id' => 2
],
[
'id' => 2,
'foreign_id' => 1
],
[
'id' => 3,
'foreign_id' => 2
],
[
'id' => 4,
'foreign_id' => 3
],
[
'id' => 5,
'foreign_id' => 2
],
]);
$a->unique('foreign_id');
The easiest way to do it is to sort collection by "id" in descending order and than use unique method by "foreign_id"
$myCollection->sortByDesc('id')->unique('foreign_id')
I am writing a script that loops through a multidimensional array and it's working as hoped (sort of) but I get errors that I just can't remedy.
I am still not that comfortable building loops to manage nested arrays.
Here is my code. The goal is to sort each layer by the value of the sequence key and in the end I export the array as json.
The sequence key may or may not exist in every sub array so that may need some sort of if clause
<?php
$list = [
"key" => "book",
"sequence" => 1,
"items" => [
[
"key" => "verse",
"sequence" => 2,
"items" => [
["sequence" => 3],
["sequence" => 1],
["sequence" => 2],
],
],
[
"key" => "page",
"sequence" => 1,
"items" => [
[
"key" => "page",
"sequence" => 2,
"items" => [
["sequence" => 2],
["sequence" => 1],
["sequence" => 3],
],
],
[
"key" => "paragraph",
"sequence" => 1,
"items" => [
["sequence" => 2],
["sequence" => 1],
["sequence" => 3],
],
],
],
],
],
];
function sortit(&$array){
foreach($array as $key => &$value){
//If $value is an array.
if(is_array($value)){
if($key == "items"){
uasort($value, function($a,&$b) {
return $a["sequence"] <=> $b["sequence"];
});
}
//We need to loop through it.
sortit($value);
} else{
//It is not an array, so print it out.
echo $key . " : " . $value . "<br/>";
}
}
}
sortit($list);
echo "<pre>";
print_r($list);
?>
Here is the output and error I am getting, and I think I understand why the error is being thrown but at the same time I can not implement the proper checks needed to fix the error.
key : book
sequence : 1
key : page
sequence : 1
E_WARNING : type 2 -- Illegal string offset 'sequence' -- at line 39
E_NOTICE : type 8 -- Undefined index: sequence -- at line 39
sequence : 1
sequence : 2
sequence : 3
sequence : 1
key : page
E_WARNING : type 2 -- Illegal string offset 'sequence' -- at line 39
E_NOTICE : type 8 -- Undefined index: sequence -- at line 39
sequence : 1
sequence : 2
sequence : 3
sequence : 2
key : verse
Not that I am worried to much but another thing that I would like is the array to still be structured in the original order, ie: key, sequence, items
Using usort and array references makes it straightforward. If we're dealing with an array with a set item key, sort the item array and recurse on its children, otherwise, we're at a leaf node and can return.
function seqSort(&$arr) {
if (is_array($arr) && array_key_exists("items", $arr)) {
usort($arr["items"], function ($a, $b) {
return $a["sequence"] - $b["sequence"];
});
foreach ($arr["items"] as &$item) {
$item = seqSort($item);
}
}
return $arr;
}
Result:
array (
'key' => 'book',
'sequence' => 1,
'items' =>
array (
0 =>
array (
'key' => 'page',
'sequence' => 1,
'items' =>
array (
0 =>
array (
'key' => 'page',
'sequence' => 1,
'items' =>
array (
0 =>
array (
'sequence' => 1,
),
1 =>
array (
'sequence' => 2,
),
2 =>
array (
'sequence' => 3,
),
),
),
),
),
1 =>
array (
'key' => 'verse',
'sequence' => 2,
'items' =>
array (
0 =>
array (
'sequence' => 1,
),
1 =>
array (
'sequence' => 2,
),
2 =>
array (
'sequence' => 3,
),
),
),
),
)
Try it!
Note that the outermost structure is a root node that isn't part of an array and can't be sorted (this may be unintentional and causing confusion).
** I have edited this to show how I got my code to work using array_search
I have an array, $arr1 with 5 columns as such:
key id name style age whim
0 14 bob big 33 no
1 72 jill big 22 yes
2 39 sue yes 111 yes
3 994 lucy small 23 no
4 15 sis med 24 no
5 16 maj med 87 yes
6 879 Ike larg 56 no
7 286 Jed big 23 yes
This array is in a cache, not a database.
I then have a second array with a list of id values -
$arr2 = array(0=>14, 1=>72, 2=>8790)
How do I filter $arr1 so it returns only the rows with the id values in $arr2?
I got my code to work as follows:
$arr1 = new CachedStuff(); // get cache
$resultingArray = []; // create an empty array to hold rows
$filter_function = function ($row) use ($arr2) {
return (array_search($row['id'], $arr2));
};
$resultingArrayIDs = $arr1->GetIds($filter_function, $resultingArray);
This gives me two outputs: $resultingArray & $resultingArrayIDs both of which represent the intersection of the $arr1 and $arr2.
This whole task can be accomplished with just one slick, native function call -- array_uintersect().
Because the two compared parameters in the custom callback may come either input array, try to access from the id column and if there isn't one declered, then fallback to the parameter's value.
Under the hood, this function performs sorting while evaluating as a means to improve execution time / processing speed. I expect this approach to outperform iterated calls of in_array() purely from a point of minimized function calls.
Code: (Demo)
var_export(
array_uintersect(
$arr1,
$arr2,
fn($a, $b) =>
($a['id'] ?? $a)
<=>
($b['id'] ?? $b)
)
);
Something like this should do it, provided I've understood your question and data structure correctly:
$dataArray = [
[ 'key' => 0, 'id' => 14 , 'name' => 'bob' , 'style' => 'big' , 'age' => 33 , 'whim' => 'no' ],
[ 'key' => 1, 'id' => 72 , 'name' => 'jill' , 'style' => 'big' , 'age' => 22 , 'whim' => 'yes' ],
[ 'key' => 2, 'id' => 39 , 'name' => 'sue' , 'style' => 'yes' , 'age' => 111 , 'whim' => 'yes' ],
[ 'key' => 3, 'id' => 994 , 'name' => 'lucy' , 'style' => 'small' , 'age' => 23 , 'whim' => 'no' ],
[ 'key' => 4, 'id' => 15 , 'name' => 'sis' , 'style' => 'med' , 'age' => 24 , 'whim' => 'no' ],
[ 'key' => 5, 'id' => 16 , 'name' => 'maj' , 'style' => 'med' , 'age' => 87 , 'whim' => 'yes' ],
[ 'key' => 6, 'id' => 879 , 'name' => 'Ike' , 'style' => 'larg' , 'age' => 56 , 'whim' => 'no' ],
[ 'key' => 7, 'id' => 286 , 'name' => 'Jed' , 'style' => 'big' , 'age' => 23 , 'whim' => 'yes' ]
];
$filterArray = [14, 72, 879];
$resultArray = array_filter( $dataArray, function( $row ) use ( $filterArray ) {
return in_array( $row[ 'id' ], $filterArray );
} );
View this example on eval.in
However, your question appears to suggest this data might be coming from a database; is that correct? If so, perhaps it's more efficient to pre-filter the results at the database-level. Either by adding a field in the SELECT query, that represents a boolean value whether a row matched your filter ids, or by simply not returning the other rows at all.
One way is with foreach loop with array_search()
$result = [];
foreach ($arr1 as $value) { // Loop thru $arr1
if (array_search($value['id'], $arr2) !== false) { // Check if id is in $arr2
$result[] = $value; // Push to result if true
}
}
// print result
print_r($result);
As #DecentDabbler mentioned - if the data is coming out of a database, using an IN on your WHERE will allow you to retrieve only the relevant data.
Another way to filter is to use array functions
array_column extracts the value of the id column into an array
array_intersect returns the elements which are in both $arr1['id'] and $arr2
array_flip flips the resulting array such that the indices into $arr1 indicate the elements in both $arr1 and $arr2
$arr1 = [ [ 'id' => 14, 'name' => 'bob'],
['id' => 72, 'name' => 'jill'],
['id' => 39, 'name' => 'sue'],
['id' => 994, 'name' => 'lucy'],
['id' => 879, 'name'=> 'large']];
$arr2 = [ 14,72,879 ];
$intersection = array_flip(array_intersect(array_column($arr1,'id'),$arr2));
foreach ($intersection as $i) {
var_dump($arr1[$i]);;
}
I have an array based MySql database.
This is the array.
[
0 => [
'id' => '1997'
'lokasi_terakhir' => 'YA4121'
]
1 => [
'id' => '1998'
'lokasi_terakhir' => 'PL2115'
]
2 => [
'id' => '1999'
'lokasi_terakhir' => 'PL4111'
]
]
How can I get the element lokasi_terakhir that grouped by the first character ? What the best way ?
This is the goal :
[
"Y" => 1,
"P" => 2
]
Please advise
Here are two refined methods. Which one you choose will come down to your personal preference (you won't find better methods).
In the first, I am iterating the array, declaring the first character of the lokasi_terakhir value as the key in the $result declaration. If the key doesn't yet exist in the output array then it must be declared / set to 1. After it has been instantiated, it can then be incremented -- I am using "pre-incrementation".
The second method first maps a new array using the first character of the lokasi_terakhir value from each subarray, then counts each occurrence of each letter.
(Demonstrations Link)
Method #1: (foreach)
foreach($array as $item){
if(!isset($result[$item['lokasi_terakhir'][0]])){
$result[$item['lokasi_terakhir'][0]]=1; // instantiate
}else{
++$result[$item['lokasi_terakhir'][0]]; // increment
}
}
var_export($result);
Method #2: (functional)
var_export(array_count_values(array_map(function($a){return $a['lokasi_terakhir'][0];},$array)));
// generate array of single-character elements, then count occurrences
Output: (from either)
array (
'Y' => 1,
'P' => 2,
)
You can group those items like this:
$array = [
0 => [
'id' => '1997',
'lokasi_terakhir' => 'YA4121'
],
1 => [
'id' => '1998',
'lokasi_terakhir' => 'PL2115'
],
2 => [
'id' => '1999',
'lokasi_terakhir' => 'PL4111'
]
];
$result = array();
foreach($array as $item) {
$char = substr($item['lokasi_terakhir'], 0, 1);
if(!isset($result[$char])) {
$result[$char] = array();
}
$result[$char][] = $item;
}
<?php
$array=[
0 => [
'id' => '1997',
'lokasi_terakhir' => 'YA4121'
],
1 => [
'id' => '1998',
'lokasi_terakhir' => 'PL2115'
],
2 => [
'id' => '1999',
'lokasi_terakhir' => 'PL4111'
]
];
foreach($array as $row){
$newArray[]=$row['lokasi_terakhir'][0];
}
print_r(array_flip(array_unique($newArray)));
this code gets the first letter of the fields lokasi_terakhir , get the unique values to avoid duplicates and just flips the array to get the outcome you want.
The output is this :
Array ( [Y] => 0 [P] => 1 )
I use the sync function for syncing a belongsToMany Relation:
$model->products()->sync($productIds);
In the $productIds array there is flat array with some Id's -
something like this:
$productIds = [1,3,5,6];
What I want:
The pivot table has also additional columns like "created_by" and "updated_by".
But how can I add these fields to my array WITHOUT doing a foreach loop?
Is there a shorter way to do this?
I need an array like this:
$productIds = [1 => [
'created_by' => 1,
'updated_by' => 1
],3 => [
'created_by' => 1,
'updated_by' => 1
],5 => [
'created_by' => 1,
'updated_by' => 1
],6 => [
'created_by' => 1,
'updated_by' => 1
]];
Yes I know I can do it with foreach and add the columns while I loop through the array. But I want do it shorter.. is there a way to do it shorter (perhaps with laravel)?
It should be enough to pass what you have set in $productIds in your code example to sync().
This method works not only with array of integers. You can also pass an array where key is the synced ID and value is the array of pivot attributes that should be set for given ID.
This should do the trick:
$productIds = [
1 => [
'created_by' => 1,
'updated_by' => 1
]
//rest of array
];
$model->products()->sync($productIds);
Just make sure you have defined those fields as pivot fields in your relation definition.
In order to generate such table based on a list of IDs in $productIds you can do the following:
$productIds = array_fill_keys($productIds, array(
'created_by' => 1,
'updated_by' => 1,
));