How to detect the empty value or unset key in array? - php

$requiredKey = ['name', 'type', 'costPrice', 'salePrice'];
$newArr = ["costPrice" => "45",
"name" => "133",
"productType" => "456",
"remark" => "4545",
"salePrice" => "454545",
"saleType" => "789"];
foreach ($requiredKey as $key) {
if($newArr[$key] == null) {
//Why this place always is true?
echo 'null';
return false;
}
$insertData[$key] = $newArr[$key];
}
Those code used to detect the value is unset or empty, and sometime the value of key is not empty, but it always return true?

isset will do in most cases, array_key_exists is more "accurate" as it will detect also null values set (as opposed to not set at all.
isset($a['x']) --> false
array_key_exist('x', $a) --> false
$a['x'] = 1;
isset($a['x']) --> true
array_key_exist('x', $a) --> true
$a['x'] = null;
isset($a['x']) --> false
array_key_exist('x', $a) --> true

You can use empty instead.
$requiredKey = ['name', 'type', 'costPrice', 'salePrice'];
$newArr = ["costPrice" => "45",
"name" => "133",
"productType" => "456",
"remark" => "4545",
"salePrice" => "454545",
"saleType" => "789"];
foreach ($requiredKey as $key) {
if(empty($newArr[$key])) {
echo 'null';
return false;
}
$insertData[$key] = $newArr[$key];
}
empty will return true if array key doesn't exists or array key exists with null value.

Related

Create a new array from a unknown depth multidimensional and keep the same structure

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

Check if value is in array using 2 specific keys

I have an array like this:
$arr = ({
"ID":"10",
"date":"04\/22\/20"
},
{
"ID":"20",
"date":"05\/25\/20"
},
{
"ID":"32",
"date":"07\/13\/20"
});
I want to know if values on 2 different keys exist in the array, how can I Achieve that?
Example: if id is equal to 32 and date equals to 07/13/20, return true.
I've tried in_array($monthName, array_column($GLOBALS['group_posts_array'], 'month')); but this only works on one key. I want to achieve to keys at once, kind of like && in if statement.
I don't think $arr in the question is a valid php array, but if it should be a multidimensional array, you might also pass for example an array to in_array with the keys and values that you are looking for:
$arr = [
[
"ID" => "10",
"date" => "04\/22\/20"
],
[
"ID" => "20",
"date" => "05\/25\/20"
],
[
"ID" => "32",
"date" => "07\/13\/20"
]
];
$values = [
"ID" => "32",
"date" => "07\/13\/20"
];
var_dump(in_array($values, $arr, true));
$values["ID"] = "33";
var_dump(in_array($values, $arr, true));
Output
bool(true)
bool(false)
You can implement a 'some' function.
function some(array $arr, callable $fn):bool{
foreach($arr as $index=>$item){
if($fn($item, $index)){
return true;
}
}
return false;
}
The usage would be something like the following:
$id = 32;
$date = "07/13/20";
$isInArray = some($arr, function($item, $index) use ($id, $date){
return $item->id == $id && $item->date == $date;
})

refactor multidimensional json in php by keys

I'm working on project and I'm trying to refactor a json object By array of $keys
for example:
as input:
{
"message": "User Detail",
"code": 200,
"error": false,
"results": {
"user": {
"id": 2,
"name": "ali",
"country": {
"id": 50,
"name": "EGY"
}
},
"access_token": "=PQLkHJYIXB2uKbCq4sXIjD2GpBU2o"
}
}
as input: array of $keys
$kyes = [
'code',
'user'=>[
'id',
'country'=>['name']
]
]
expect to return:
{
"code": 200,
"user": {
"id": 2,
"country": {
"name": "egy",
}
}
}
code I have tried:
public function filter_multidimensional(array $array, array $keys){
$val = [];
foreach ($array as $key => $value) {
if (in_array($key,$keys)){
$val[$key] = $value;
}elseif (is_array($value)) {
$val[$key] = $this->filter_multidimensional($keys,$value);
}
}
return $val;
}
//-------
$this->filter_multidimensional($json,['code','user'=>['id','country'=>['name']]])
Unfortunately output:
update 1
the json input is not const, so my code must be adapt. and that's I'm trying to do.
Thanks for #404-not-found his code was amazing but missing a small thing
which is in this code
if (is_array($key)) {
$val[$objectKey] = filter_multidimensional($array, $key);
}
you still give the find function the base array which will return the first value it will find in the case of ['user'=>['id',"country"=>['id']]] and the solution for this will be passing the parent array of the object key
So the full code will be
<?php
function filter_multidimensional(array $array, array $keys) {
if (empty($keys) || empty($array)) {
return [];
}
$val = [];
// In the structure of $keys, both key and value are technically "keys".
// In the example `['code','user'=>['id']]`, 'code' and 'id' are both array *values*,
// while 'user' is a key.
//
// So, $objectKey is a search key which contains sub-keys, while $key is just a regular string.
foreach ($keys as $objectKey => $key) {
// If $key is an array, then recursively search, and save the results to the $objectKey string.
if (is_array($key)) {
$val[$objectKey] = filter_multidimensional(findTill($array,$objectKey), $key);
}
// If the desired key exists, then save the value.
else if (array_key_exists($key, $array)) {
$val[$key] = $array[$key];
}
// Otherwise, $key is a string, but it does not exist at this level of $array,
// so search the next-level up in $array, and merge the results into this level of $val.
else {
$val = array_merge($val, filter_multidimensional(nextLevel($array), [$key]));
}
}
return $val;
}
function findTill($array,$key) {
if (array_key_exists($key, $array)) {
return $array[$key];
}
return findTill(nextLevel($array),$key);
}
/**
* Create an array that contains only the array values from $array.
*
* Eg: If given ['a' => '1', 'b' => ['foo' => '2'], 'c' => ['hello' => 'world']],
* then return ['foo' => '2', 'hello' => 'world']
*
* #param array $array
* #return array
*/
function nextLevel(array $array) {
// Merge all of the array values together into one array
return array_reduce(
// Strip the keys
array_values(
// Filter to return only keys where the value is an array
array_filter(
$array,
function ($value) {
return is_array($value);
}
)
),
'array_merge',
[]
);
}
//-------
$obj = [
"message" => "User Detail",
"code" => 200,
"error" => false,
"results" => [
"user" => [
"id" => 2,
"name" => "ali",
"country" => [
"id" => 50,
"name" => "EGY",
],
],
"access_token" => "=PQLkHJYIXB2uKbCq4sXIjD2GpBU2o",
],
];
$result = filter_multidimensional($obj,['code','user'=>['id','country'=>['id','name']],"access_token"]);
I believe this method works. I flipped your logic, and instead of searching the $array to see if it's keys match any of those in $keys, I instead recursively searched $keys to see if $array had any matching values.
function filter_multidimensional(array $array, array $keys) {
if (empty($keys) || empty($array)) {
return [];
}
$val = [];
// In the structure of $keys, both key and value are technically "keys".
// In the example `['code','user'=>['id']]`, 'code' and 'id' are both array *values*,
// while 'user' is a key.
//
// So, $objectKey is a search key which contains sub-keys, while $key is just a regular string.
foreach ($keys as $objectKey => $key) {
// If $key is an array, then recursively search, and save the results to the $objectKey string.
if (is_array($key)) {
$val[$objectKey] = filter_multidimensional($array, $key);
}
// If the desired key exists, then save the value.
else if (array_key_exists($key, $array)) {
$val[$key] = $array[$key];
}
// Otherwise, $key is a string, but it does not exist at this level of $array,
// so search the next-level up in $array, and merge the results into this level of $val.
else {
$val = array_merge($val, filter_multidimensional(nextLevel($array), [$key]));
}
}
return $val;
}
/**
* Create an array that contains only the array values from $array.
*
* Eg: If given ['a' => '1', 'b' => ['foo' => '2'], 'c' => ['hello' => 'world']],
* then return ['foo' => '2', 'hello' => 'world']
*
* #param array $array
* #return array
*/
function nextLevel(array $array) {
// Merge all of the array values together into one array
return array_reduce(
// Strip the keys
array_values(
// Filter to return only keys where the value is an array
array_filter(
$array,
function ($value) {
return is_array($value);
}
)
),
'array_merge',
[]
);
}
//-------
$result = filter_multidimensional($obj,['code','user'=>['id','country'=>['name']]]);
You could use a combination of data_get and data_set to get what you want.
Change the input a bit so it's more consistent. Dot notation would be easiest.
$array = [
"message" => "User Detail",
"code" => 200,
"error" => false,
"results" => [
"user" => [
"id" => 2,
"name" => "ali",
"country" => [
"id" => 50,
"name" => "EGY",
],
],
"access_token" => "=PQLkHJYIXB2uKbCq4sXIjD2GpBU2o",
],
];
$keys = [
'code' => 'code',
'user.id' => 'results.user.id',
'user.country.name' => 'results.user.country.name',
];
$results = [];
foreach ($keys as $set_position => $get_position) {
data_set($results, $set_position, data_get($array, $get_position));
}

How to check index exist or not in my array

I have two arrays
one show all the quiz. another one shows the all taken quiz. now I like o show this for each array that where all quiz list neet to show but match the done quiz table, if available it will return status true. I am using array_key_exist but its showing error.
$getquizId = [
'id' => '',
'title' => '',
'status' => ''
];
$allquizId = [];
$totalQuiz = Quize::where('course_id', $course_id)->with('resources')->get();
$doneQuiz = QuizProgress::where('user_id', $user_id)->where('course_id', $course_id)->with('course')->get();
$progress = (count($doneQuiz) / count($totalQuiz)) * 100;
foreach ($totalQuiz as $key => $value) {
$getquizId = [
'id' => $value->id,
'title' => $value->title,
'status' => (array_key_exists($key, $doneQuiz) ? ($value->id == $doneQuiz[$key]['id'] ? true : false) : false)
];
// if (array_key_exists($key, $doneQuiz)) {
// ($value->id == $doneQuiz[$key]['quiz_id'] ? $getquizId['status'] = 'true' : $getquizId['status'] = 'false');
// }
array_push($allquizId, $getquizId);
}
return $allquizId;
In here (array_key_exists($key, $doneQuiz) ? ($value->id == $doneQuiz[$key]['id'] ? true : false) : false) I need to check the array key exist o not.
I want to show the array like this
[
{
"id": 4,
"title": "Digital Marketing",
"status": true
},
{
"id": 5,
"title": "Personal Leadership",
"status": false
}
]
First get the id of the quiz which is done, and then check the array with in_array
But I would suggest you make the proper relationship
$doneQuiz = QuizProgress::where('user_id', $user_id)->where('course_id', $course_id)->with('course')->pluck('quiz_id')->toArray();
$getquizId = [
'id' => $value->id,
'title' => $value->title,
'status' => in_array($value->id, $doneQuiz) ? true : false
];
Dear always try to do some proper code.
$bool = false;
if(isset($doneQuiz[$key]['id']) && $value->id === $doneQuiz[$key]['id'] )
$bool = true;
put above code before $getquizId array and add $bool variable in value of status.
Note: check the $doneQuiz getting in array format.

Check if a value is empty for a key in a multidimensional array

I need a simple and elegant solution to check if a key has an empty value in a multidimensional array. Should return true/false.
Like this, but for a multidimensional array:
if (empty($multi_array["key_inside_multi_array"])) {
// Do something if the key was empty
}
All the questions I have found are searching for a specific value inside the multi-array, not simply checking if the key is empty and returning a true/false.
Here is an example:
$my_multi_array = array(
0 => array(
"country" => "",
"price" => 4,
"discount-price" => 0,
),
);
This will return true:
$my_key = "country";
if (check_multi_array_for_empty_value($my_multi_array, $my_key)) {
//Run this code here because the "country" key in my multi dimensional array is empty
}
This will also return true:
$my_key = "discount-price";
if (check_multi_array_for_empty_value($my_multi_array, $my_key)) {
//Run this code here because the "discount-price" key in my multi dimensional array is empty
}
This will return false:
$my_key = "price";
if (check_multi_array_for_empty_value($my_multi_array, $my_key)) {
//This WILL NOT RUN because the "price" key in my multi dimensional array is NOT empty
}
When I say empty, I mean like this empty()
UPDATE:
I am trying to adapt the code from this question but so far without any luck. Here is what I have so far, any help fixing would be appreciated:
function bg_empty_value_check($array, $key)
{
foreach ($array as $item)
{
if (is_array($item) && bg_empty_value_check($item, $key)) return true;
if (empty($item[$key])) return true;
}
return false;
}
You have to call recursive function for example i have multi dimension array
function checkMultiArrayValue($array) {
global $test;
foreach ($array as $key => $item) {
if(!empty($item) && is_array($item)) {
checkMultiArrayValue($item);
}else {
if($item)
$test[$item] = false;
else
$test[$item] = true;
}
}
return $test;
}
$multiArray = array(
0 => array(
"country" => "",
"price" => 4,
"discount-price" => 0,
),);
$test = checkMultiArrayValue($multiArray);
echo "<pre>"
print_r($test);
Will return array with true and false, who have key and index will contain true and who have index but not value contain false, you can use this array where you check your condition
Below function may help you to check empty value in nested array.
function boolCheckEmpty($array = [], $key = null)
{
if (array_key_exists($key, $array) && !empty($array[$key])) {
return true;
}
if (is_array($array)) {
foreach ((array)$array as $arrKey => $arrValue) {
if (is_array($arrValue)) {
return boolCheckEmpty($arrValue, $key);
}
if ($arrKey == $key && !empty($arrValue)) {
return $arrValue;
}
}
}
return false;
}
Usage :
$my_multi_array = array(
0 => array(
"country" => "aa",
"price" => 1,
"discount-price" => 0,
),
);
// Call
$checkEmpty = $this->boolCheckEmpty($my_multi_array, 'price');
var_dump($checkEmpty);
Note : This function also return false if value is 0 because used of empty

Categories