seem to be experiencing something strange. I am loading an Excel file's data into an array. I am handling things like so
foreach ($data->toArray() as $value) {
dd($value);
if(!empty($value)){
foreach ($value as $v) {
dd($v['id']);
$insert[] = [
'id' => $v['id'],
'name' => $v['name']
];
}
}
}
Now the first dd() (laravel output) produces something like so
array:809 [▼
0 => array:20 [▼
"id" => "123"
"name" => "something"
]
...
So I can see there is an array element called id. The second dd, which calls this array element, produces the output 123
The problem comes where I am filling the array with this data. Although I am still using $v['id'] which works for the output, within the array I get the error
Undefined index: id
Why would this be the case when the index is there?
Thanks
Try to add an if to check if the keys really exist in your array. This will avoid situations when the key does not exist and the Undefined index: id error appear.
foreach ($data->toArray() as $value) {
if(!empty($value)){
foreach ($value as $v) {
if (array_key_exists("id",$v) &&
array_key_exists("name",$v)) {
$insert[] = [
'id' => $v['id'],
'name' => $v['name']
];
}
}
}
}
Related
Here my array:
$array = [
'key1' => [
'first' => 'azerty',
'second' => 'qwerty'
],
'key2' => [
'first' => 'hello',
'second' => 'world'
]
];
With the value 'qwerty' I would like to retrieve the 'key1'.
I looking for something like that:
$theKeyIWant = array_search('qwerty', array_column($array, 'second'));
But I get '0', instead of 'key1' (and I know that's how it works)
Anyone know how to adapt this code or know another code to get the key value?
Slight modification to your code to combine the keys and column values:
$theKeyIWant = array_search('qwerty', array_combine(array_keys($array), array_column($array, 'second')));
The problem with seeking "something sexier" for this task is that if "sexier" means a "functional iterator", then that comes a cost of not being able to "return early" (doing unnecessary cycles).
If you want a single-line function to call, you can build your own and put it in a helpers file somewhere in your project. My strong advice is to abandon "sexy" for this task and use a breakable foreach loop.
Code: (Demo)
function getRowKey($array, $column, $value) {
foreach ($array as $key => $row) {
if ($row[$column] === $value) {
return $key;
}
}
return null;
}
var_export(getRowKey($array, 'second', 'qwerty'));
If you are going to perform repeated searches on the same array and the second column is guaranteed to contain unique values, then you can convert the array into a lookup array without losing any data. (Demo)
function restructure($array, $columnToKey) {
$result = [];
foreach ($array as $key => $row) {
$result[$row[$columnToKey]] = $row + ['oldKey' => $key];
}
return $result;
}
var_export(restructure($array, 'second')['qwerty']);
To solve this is to loop through the outer array and use array_search() to search for the value within each inner array.
$value = 'qwerty';
$theKeyIWant = null;
foreach ($array as $key => $innerArray) {
if (array_search($value, $innerArray) !== false) {
$theKeyIWant = $key;
break;
}
}
echo $theKeyIWant; // Output: key1
array_keys returns an array of an array's keys.
<?php
$array = [
'key1' => [
'first' => 'azerty',
'second' => 'qwerty'
],
'key2' => [
'first' => 'hello',
'second' => 'world'
]
];
$theKeyIWant = array_search('qwerty', array_column($array, 'second'));
echo array_keys($array)[$theKeyIWant];
?>
3V4l
I have a multidimensional array that can have any depth. What im trying to do is to filter the whole path based on dynamic keys and create a new array of it.
Example of the array
$originalArray = [
"title" => "BACKPACK MULTICOLOUR",
"description" => "description here",
"images" => [
[
"id" => 12323123123,
"width" => 635,
"height" => 560,
"src" => "https://example.com",
"variant_ids": [32694976315473, 32863017926737],
],
[
"id" => 4365656656565,
"width" => 635,
"height" => 560,
"src" => "https://example.com",
"variant_ids": [32694976315473, 32863017926737],
]
],
"price" => [
"normal" => 11.00,
"discount" => [
"gold_members" => 9.00,
"silver_members" => 10.00,
"bronze_members" => null
]
]
];
Example how the output should look like with the key "title, width, height, gold_members" filtered out. Only keys from the end of the array tree should be valid, so nothing must happen when images is in the filter
$newArray = [
"title" => "BACKPACK MULTICOLOUR",
"images" => [
[
"width" => 635,
"height" => 560,
],
[
"width" => 635,
"height" => 560,
]
],
"price" => [
"discount" => [
"gold_members" => 9.00,
]
]
];
I guess that i should create a function that loop through each element and when it is an associative array, it should call itself again
Because the filtered paths are unknown i cannot make a hardcoded setter like this:
$newArray["images"][0]["width"] = 635
The following filter will be an example but it should basically be dynamic
example what i have now:
$newArray = handleArray($originalArray);
handleArray($array)
{
$filter = ["title", "width", "height", "gold_members"];
foreach ($array as $key => $value) {
if (is_array($value)) {
$this->handleArray($value);
} else {
if (in_array($key, $filter)) {
// put this full path in the new array
}
}
}
}
[Solved] Update:
I solved my problem thanks to #trincot
I used his code and added an extra check to add an array with multiple values to the new array
My code to solve the issue:
<?php
function isListOfValues($array) {
$listOfArrays = [];
foreach ($array as $key => $value) {
$listOfArrays[] = ! is_array($value) && is_int($key);
}
return array_sum($listOfArrays) === count($listOfArrays);
}
function filterKeysRecursive(&$arr, &$keep) {
$result = [];
foreach ($arr as $key => $value) {
if (is_array($value) && ! isListOfValues($value)) {
$value = filterKeysRecursive($value, $keep);
if (count($value)) {
$result[$key] = $value;
}
} else if (array_key_exists($key, $keep)) {
$result[$key] = $value;
}
}
return $result;
}
$keep = array_flip(["title", "width", "height", "gold_members"]);
$result = filterKeysRecursive($originalArray, $keep);
You could use a recursive function, with following logic:
base case: the value associated with a key is not an array (it is a "leaf"). In that case the new object will have that key/value only when the key is in the list of desired keys.
recursive case: the value associated with a key is an array. Apply recursion to that value. Only add the key when the returned result is not an empty array. In that case associate the filtered value to the key in the result object.
To speed up the look up in the list of keys, it is better to flip that list into an associative array.
Here is the implementation:
function filter_keys_recursive(&$arr, &$keep) {
foreach ($arr as $key => $value) {
if (is_array($value)) {
$value = filter_keys_recursive($value, $keep);
if (count($value)) $result[$key] = $value;
} else if (array_key_exists($key, $keep)) {
$result[$key] = $value;
}
}
return $result;
}
$originalArray = ["title" => "BACKPACK MULTICOLOUR","description" => "description here","images" => [["id" => 12323123123,"width" => 635,"height" => 560,"src" => "https://example.com"],["id" => 4365656656565,"width" => 635,"height" => 560,"src" => "https://example.com"]],"price" => ["normal" => 11.00,"discount" => ["gold_members" => 9.00,"silver_members" => 10.00,"bronze_members" => null]]];
$keep = array_flip(["title", "width", "height", "gold_members"]);
$result = filter_keys_recursive($originalArray, $keep);
My proposition to you is to write a custom function to transform structure from one schema to another:
function transform(array $originalArray): array {
array_walk($originalArray['images'], function (&$a, $k) {
unset($a['id']); unset($a['src']);
});
unset($originalArray['description']);
unset($originalArray['price']['normal']);
unset($originalArray['price']['discount']['silver_members']);
unset($originalArray['price']['discount']['bronze_members']);
return $originalArray;
}
var_dump(transform($originalArray));
If you are familiar with OOP I suggest you to look at how DTO works in API Platform for example and inject this idea into your code by creating custom DataTransformers where you specify which kind of structers you want to support with transformer and a method where you transform one structure to another.
Iterate over the array recursively on each key and subarray.
If the current key in the foreach is a required key in the result then:
If the value is not an array, simply assign the value
If the value is an array, iterate further down over value recursively just in case if there is any other filtering of the subarray keys that needs to be done.
If the current key in the foreach is NOT a required key in the result then:
Iterate over value recursively if it's an array in itself. This is required because there could be one of the filter keys deep down which we would need. Get the result and only include it in the current subresult if it's result is not an empty array. Else, we can skip it safely as there are no required keys down that line.
Snippet:
<?php
function filterKeys($array, $filter_keys) {
$sub_result = [];
foreach ($array as $key => $value) {
if(in_array($key, $filter_keys)){// if $key itself is present in $filter_keys
if(!is_array($value)) $sub_result[$key] = $value;
else{
$temp = filterKeys($value, $filter_keys);
$sub_result[$key] = count($temp) > 0 ? $temp : $value;
}
}else if(is_array($value)){// if $key is not present in $filter_keys - iterate over the remaining subarray for that key
$temp = filterKeys($value, $filter_keys);
if(count($temp) > 0) $sub_result[$key] = $temp;
}
}
return $sub_result;
}
$result = filterKeys($originalArray, ["title", "width", "height", "gold_members"]);
print_r($result);
Online Demo
Try this way.
$expectedKeys = ['title','images','width','height','price','gold_members'];
function removeUnexpectedKeys ($originalArray,$expectedKeys)
{
foreach ($originalArray as $key=>$value) {
if(is_array($value)) {
$originalArray[$key] = removeUnexpectedKeys($value,$expectedKeys);
if(!is_array($originalArray[$key]) or count($originalArray[$key]) == 0) {
unset($originalArray[$key]);
}
} else {
if (!in_array($key,$expectedKeys)){
unset($originalArray[$key]);
}
}
}
return $originalArray;
}
$newArray = removeUnexpectedKeys ($originalArray,$expectedKeys);
print_r($newArray);
check this on editor,
https://www.online-ide.com/vFN69waXMf
I try foreach loop but it keeps giving me "Undefined offset 2".
I tried also isset then I got "Undefined offset 1"
My code:
foreach ($lineArrayResults as $lineArrayResultKey => $lineArrayResult)
{
$currentFormFieldId = $submittedFormFields[$lineArrayResultKey]; // this line gives me error.
if($currentFormFieldId > 0)
{
$newLeadDataArray[$currentFormFieldId] = [
'field_name' => $formFields[$currentFormFieldId],
'field_value' => $lineArrayResult
];
}
}
the error undefined offset means that an array have ran out of bounds. the array size is smaller than the index that you are trying to fetch an object from.
First of all make sure your $submittedFormFields array contains the key of $lineArrayResultKey variable, if the array key is dynamically generated then try this code
foreach ($lineArrayResults as $lineArrayResultKey => $lineArrayResult)
{
if(!array_key_exists($lineArrayResultKey, $submittedFormFields)){
continue;
}
$currentFormFieldId = $submittedFormFields[$lineArrayResultKey];
if($currentFormFieldId > 0)
{
$newLeadDataArray[$currentFormFieldId] = [
'field_name' => $formFields[$currentFormFieldId],
'field_value' => $lineArrayResult
];
}
}
add # before $
try this
foreach ($lineArrayResults as $lineArrayResultKey => $lineArrayResult)
{
$currentFormFieldId = #$submittedFormFields[$lineArrayResultKey]; // insert # before $
if($currentFormFieldId > 0)
{
$newLeadDataArray[$currentFormFieldId] = [
'field_name' => $formFields[$currentFormFieldId],
'field_value' => $lineArrayResult
];
}
}
I need to check if there is a 'CodProduto', so i did:
foreach ($movimentos['CodProduto'] as $value){}
It will run all CodProduto and If it exists i need to do a if inside the foreach to check 2 others fields:
if (!$movimentos['Percentagem'] && !$movimentos['Valor'] {...}
My problem is that i dont know how to access the $movimentos['Percentagem'] and !movimentos['Valor'] items/index or sub-index i dont know how to call it.
$movimentos['Valor'] is an array and i dont know how to check his items at same time as i check $movimentos['Percentagem']
i know there is $movimentos['Valor'][$i] in for but how can i do it in for each? is it possible?
foreach allows you to specify a variable to get the index:
foreach ($movimentos['CodProduto'] as $index => $value) {
if (!$movimentos['Percentagem'][$index] && !$movimentos['Valor'][$index]) {...}
}
However, it's usually easier if you put all the related data in a single array, rather than in separate arrays. So instead of
$movimentos = [
"CodProduto" => [...],
"Percentagem" => [...],
"Valor" => [...],
"ProdutoDesignaceo" => [...]
];
do it like this:
$movimentos = [
["CodProduto" => 1, "Percentagem" => 1, "Valor" => 2, "ProdutoDesignaceo" => "..."],
["CodProduto" => 2, "Percentagem" => 3, "Valor" => 4, "ProdutoDesignaceo" => "..."],
...
];
Then your loop would be like:
foreach ($movimentos as $m) {
if (!$m['Percentagem'] && !$m['Valor']) {...}
}
try this:
foreach ($movimentos['CodProduto'] as $index => $value) {
echo $index
}
You can iterate over the items and get the Index for each item.
Use this index ($i) to access the values from the other arrays while you iterate over the CodProduto sub-array.
foreach ($movimentos['CodProduto'] as $i => $value) {
$percentagem = $movimentos['Percentagem'][$i];
$valor = $movimentos['Valor'][$i];
// Do anything you like with these values here
// E.g.
if (!$percentagem && !$valor) {
// ...
}
}
I have an array of multiple arrays all with different levels. What im trying to do is loop though the array by key, and it will go through each level getting the values for those keys. myArray looks something like this
Array ( [0] =>
Array ( [Date] => 2011-15-22
[Color] => blue
[Status] => Fresh
[1] =>
Array ( [Date] => 1999-08-04
[Color] => green
[Status] => Rotten) )
I have tried
foreach($myArray as $row){
foreach($row["Date"] as $k){
echo $k
}
}
I am getting an
Notice: Undefined index: Date
and
Warning: Invalid argument supplied for foreach()
Simply with array_walk_recursive function:
$arr = [
[ 'Date' => '2011-15-22', 'Color' => 'blue', 'Status' => 'Fresh' ],
[ 'Date' => '1999-08-04', 'Color' => 'green', 'Status' => 'Rotten' ]
];
array_walk_recursive($arr, function($v, $k){
if ($k == 'Date') echo $v . PHP_EOL;
});
The output:
2011-15-22
1999-08-04
On your foreach, you should specify the key and value so you can access both:
foreach ($myArray as $key => $value){
echo $key.' is '. gettype ($value).'<br>';
if (is_array($value)){
foreach ($value as $subKey => $subValue){
echo $subkey . ' => ' . $subValue . '<br>';
}
}
}
This way you can access and print all values without losing the structure
As axiac states in the comments, $row["Date"]is a String and therefore not iterable. You probably just want this:
foreach($myArray as $row){
foreach($row as $k){
echo $k
}
}
The Notice Undefined index: Date also describes what is going wrong - you are accessing the index without checking if it exists. It does look like that your data structure is not always the same. In this case you should always check the existence with the isset function:
if (isset($row["Date"])) {
//do something here
}
It looks like you just need this:
foreach($myArray as $row){
echo $row["Date"];
}
or
foreach($myArray as $row){
$k= $row["Date"];
//do stuff...
}
or
foreach($myArray as $row){
$k[]= $row["Date"];
}
// do stuff with $k[] array.
Warning: Invalid argument supplied for foreach()
Because $row["Date"] is string
foreach() - foreach works only on arrays and objects, and will issue an error when you try to use it on a variable with a different data type or an uninitialized variable.
Notice: Undefined index: Date
Probably your array may not have element with key Date somewhere (your array structure probably different, as iteration takes place), so you are getting this message, use isset() to or array_key_exists() to validate, depending on the purpose.
Please note isset != array_key_exists
$a = array('key1' => 'test1', 'key2' => null);
isset($a['key2']); // false
array_key_exists('key2', $a); // true
There is another important difference. isset doesn't complain when $a does not exist, while array_key_exists does.