PHP Remove elements from associative array - php

I have an PHP array that looks something like this:
Index Key Value
[0] 1 Awaiting for Confirmation
[1] 2 Assigned
[2] 3 In Progress
[3] 4 Completed
[4] 5 Mark As Spam
When I var_dump the array values i get this:
array(5) { [0]=> array(2) { ["key"]=> string(1) "1" ["value"]=> string(25) "Awaiting for Confirmation" } [1]=> array(2) { ["key"]=> string(1) "2" ["value"]=> string(9) "Assigned" } [2]=> array(2) { ["key"]=> string(1) "3" ["value"]=> string(11) "In Progress" } [3]=> array(2) { ["key"]=> string(1) "4" ["value"]=> string(9) "Completed" } [4]=> array(2) { ["key"]=> string(1) "5" ["value"]=> string(12) "Mark As Spam" } }
I wanted to remove Completed and Mark As Spam. I know I can unset[$array[3],$array[4]), but the problem is that sometimes the index number can be different.
Is there a way to remove them by matching the value name instead of the key value?

Your array is quite strange : why not just use the key as index, and the value as... the value ?
Wouldn't it be a lot easier if your array was declared like this :
$array = array(
1 => 'Awaiting for Confirmation',
2 => 'Asssigned',
3 => 'In Progress',
4 => 'Completed',
5 => 'Mark As Spam',
);
That would allow you to use your values of key as indexes to access the array...
And you'd be able to use functions to search on the values, such as array_search() :
$indexCompleted = array_search('Completed', $array);
unset($array[$indexCompleted]);
$indexSpam = array_search('Mark As Spam', $array);
unset($array[$indexSpam]);
var_dump($array);
Easier than with your array, no ?
Instead, with your array that looks like this :
$array = array(
array('key' => 1, 'value' => 'Awaiting for Confirmation'),
array('key' => 2, 'value' => 'Asssigned'),
array('key' => 3, 'value' => 'In Progress'),
array('key' => 4, 'value' => 'Completed'),
array('key' => 5, 'value' => 'Mark As Spam'),
);
You'll have to loop over all items, to analyse the value, and unset the right items :
foreach ($array as $index => $data) {
if ($data['value'] == 'Completed' || $data['value'] == 'Mark As Spam') {
unset($array[$index]);
}
}
var_dump($array);
Even if do-able, it's not that simple... and I insist : can you not change the format of your array, to work with a simpler key/value system ?

...
$array = array(
1 => 'Awaiting for Confirmation',
2 => 'Asssigned',
3 => 'In Progress',
4 => 'Completed',
5 => 'Mark As Spam',
);
return array_values($array);
...

$key = array_search("Mark As Spam", $array);
unset($array[$key]);
For 2D arrays...
$remove = array("Mark As Spam", "Completed");
foreach($arrays as $array){
foreach($array as $key => $value){
if(in_array($value, $remove)) unset($array[$key]);
}
}

You can use this
unset($dataArray['key']);

Why do not use array_diff?
$array = array(
1 => 'Awaiting for Confirmation',
2 => 'Asssigned',
3 => 'In Progress',
4 => 'Completed',
5 => 'Mark As Spam',
);
$to_delete = array('Completed', 'Mark As Spam');
$array = array_diff($array, $to_delete);
Just note that your array would be reindexed.

Try this:
$keys = array_keys($array, "Completed");
/edit
As mentioned by JohnP, this method only works for non-nested arrays.

I kinda disagree with the accepted answer. Sometimes an application architecture doesn't want you to mess with the array id, or makes it inconvenient. For instance, I use CakePHP quite a lot, and a database query returns the primary key as a value in each record, very similar to the above.
Assuming the array is not stupidly large, I would use array_filter. This will create a copy of the array, minus the records you want to remove, which you can assign back to the original array variable.
Although this may seem inefficient it's actually very much in vogue these days to have variables be immutable, and the fact that most php array functions return a new array rather than futzing with the original implies that PHP kinda wants you to do this too. And the more you work with arrays, and realize how difficult and annoying the unset() function is, this approach makes a lot of sense.
Anyway:
$my_array = array_filter($my_array,
function($el) {
return $el["value"]!="Completed" && $el!["value"]!="Marked as Spam";
});
You can use whatever inclusion logic (eg. your id field) in the embedded function that you want.

The way to do this to take your nested target array and copy it in single step to a non-nested array.
Delete the key(s) and then assign the final trimmed array to the nested node of the earlier array.
Here is a code to make it simple:
$temp_array = $list['resultset'][0];
unset($temp_array['badkey1']);
unset($temp_array['badkey2']);
$list['resultset'][0] = $temp_array;

for single array Item use reset($item)

Related

Extract item from multi-dimensional array from custom depth

I have multidimensional array like this:
$obj = array(
"a" => array(
"aa" => array(
"aaa" => 1
),
"bb" => 2,
),
"b" => array(
"ba" => 3,
"bb" => 4,
),
"c" => array(
"ca" => 5,
"cb" => 6,
),
);
I can not figured out a neatest way, e.g. custom-depth function, to extract item at specific location with arguments to function (or array of key names). For example:
echo $obj[someFunc("a", "aa", "aaa")];
... should return 1.
print_r($obj[someFunc("a")]);
... should return:
Array
(
[aa] => Array
(
[aaa] => 1
)
[bb] => 2
)
What is the best way to accomplished this with php7 features?
Since PHP 5.6, ["Variadic functions"][1] have existed. These provide us with a nice simple to read way to collect arguments used in calling a function into a single array. For example:
function getValue(...$parts) {
var_dump($parts);
}
getValue('test', 'part');
Will output:
array(2) {
[0]=>
string(4) "test"
[1]=>
string(4) "part"
}
This was all possible before using built-in functions to get the parameters, but this is more readable.
You could also be a little more explicit with the argument types, but I'll leave that for you to figure out if necessary.
You next major challenge is to loop through the arguments. Something like this will produce the value that you desire.
function getValue(...$parts) {
$returnValue = $obj;
foreach ($parts as $part) {
$returnValue = $obj[$part];
}
return $returnValue;
}
However, this is rather crude code and will error when you try calling it to access non-existent parts. Have a play and fix those bits.
[1]: https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list

Search for array row with specific column value and return another value from qualifying row

I have a multidimensional array that I am trying to search for a specific value (url) and then retrieve an another value in the same row (value). I also need to divert to an else if it is not found.
array(2) {
[0]=> array(2) {
["url"]=> string(7) "fareham"
["value"]=> string(7) "Fareham"
}
[1]=> array(2) {
["url"]=> string(11) "southampton"
["value"]=> string(11) "Southampton"
}
}
I have been experimenting with array_key_exists() and isset() to check it's set and just coming up null!
For example, if I search for fareham, I want to return Fareham. If I search for nottingham, I expect null.
How can I isolate the qualifying value?
Use array_column() to index the data by the url columns and then use isset() to check if the value is there...
$data = array_column($data, "value", "url");
$search = 'southampton';
$value = isset($data[$search])?$data[$search]:"not found";
echo $value;
or for PHP 7+, you can use the null coalescing operator (??)
$value = $data[$search]??"not found";
Here is the minimal way to do it (no checks)
$a = array (
0 =>
array (
"url" => 'fareham',
"value" => 'Fareham'
),
1 =>
array (
"url" => 'southampton',
"value" => 'Southampton'
)
);
$u = 'fareham';
$i = $a[false===($f=array_search($u,array_column($a,'url')))?-1:$f]['value'];
print_r($i);
Output
Fareham
Sandbox
How it works
First we create an array we can search by using array_column on the column we want to search in this case url. It looks like this [0=>'fareham', 1=>'southampton']
Then we use the normal array_search which returns an index, if you notice above the indexes are correlated to the original array. Which means we can put that in as the top level key, then it's a simple matter of adding the key we want.
Because array_search can return a boolean(false) which PHP sees as 0 or the first index I put a little hack in for that. But a better way is to check it like this:
$a = array (
0 =>
array (
"url" => 'fareham',
"value" => 'Fareham',
"extra" => 'Foo'
),
1 =>
array (
"url" => 'southampton',
"value" => 'Southampton',
"extra" => 'Bar'
)
);
function serchMultiDimensionalValue($needle, $haystack, $fields='value'){
if(false === ($f=array_search($needle,array_column($haystack,'url')))) return false; //or return [];
if(!is_array($fields)) $fields = [$fields];
return array_intersect_key($haystack[$f], array_flip($fields));
}
var_dump(serchMultiDimensionalValue('foo',$a));
var_dump(serchMultiDimensionalValue('fareham',$a));
var_dump(serchMultiDimensionalValue('fareham',$a, 'extra'));
var_dump(serchMultiDimensionalValue('fareham',$a, ['extra','url']));
Ouput
bool(false)
array(1) {
["value"]=>
string(7) "Fareham"
}
array(1) {
["extra"]=>
string(3) "Foo"
}
array(2) {
["url"]=>
string(7) "fareham"
["extra"]=>
string(3) "Foo"
}
Sandbox
I added a bit more "functionality" to it, hope you don't mind.
While it might be alluring to seek out a one-liner like:
array_column($array, $returnColumn, $haystackColumn)[$needle] ?? null
Be aware that array_column() will be unconditionally doubling the memory usage (because it is generating a new array with the same length as the original) for the sake of assigning new first level keys to search by.
Metaphorically speaking, it is like building a new registry of residences in a neighborhood including every homeowner's name and their address. Yes, you can find out who lives at a given home without knocking on the front door, but you had to knock on every door to collect every home's details before enjoying this convenience. Why not just knock on the door of each original house and ask if they are who you are looking for? It is much easier, and you will be able to "quit" early as soon as you find the homeowner that you are looking for.
For best efficiency and for least memory usage, I recommend the below classic loop with conditional break. It is built with dynamic search and return variables for general usage, but you can use hardcoded values if you like.
Code: (Demo)
$array = [
["url" => 'fareham', "value" => 'Fareham'],
["url" => 'southampton', "value" => 'Southampton']
];
$needle = 'fareham';
$haystackColumn = 'url';
$returnColumn = 'value';
$value = null;
foreach ($array as $row) {
if ($row[$haystackColumn] === $needle) {
$value = $row[$returnColumn];
break;
}
}
var_export($value); // 'Fareham'

Sorting an array by the values of another array

I have a some messy data coming in from a feed, and am trying to figure out how to sort it correctly. I posted a simplified example below. I'd like to sort the people array alphabetically by the Group name.
$people = array(
"category_id_1" => array (
"Mark",
"Jenny",
"Andrew"
),
"category_id_2" => array (
"John",
"Lewis",
"Andrea"
),
"category_id_3" => array (
"Hannah",
"Angie",
"Raleigh"
)
);
$categories = array(
"category_id_1" => "Group B",
"category_id_2" => "Group C",
"category_id_3" => "Group A"
);
Ideally, the end result would be
$people = array(
"category_id_3" => array ( // Group A
"Hannah",
"Angie",
"Raleigh"
),
"category_id_1" => array ( // Group B
"Mark",
"Jenny",
"Andrew"
),
"category_id_2" => array ( // Group C
"John",
"Lewis",
"Andrea"
)
);
I've been spinning my wheels for a while now, and the closest I have gotten is this uasort, which still isn't doing the trick.
uasort($people, function ($a, $b) {
return strcmp($categories[$a], $categories[$b]);
});
Thanks so much for any help.
This can be achieved in a simpler way by taking advantage of array_replace:
// Work on a copy just to be sure the rest of your code is not affected
$temp_categories = $categories;
// Sort categories by name
asort($temp_categories);
// Replace the values of the sorted array with the ones in $people
$ordered_people = array_replace($temp_categories, $people);
You want to sort $people by its keys not its values. You can use uksort for this. Additionally you need to make $categories available in your function. I prefer use for that; but you could also make it a global variable. Final code:
uksort($people, function ($a,$b) use ($categories) {
return strcmp($categories[$a], $categories[$b]);
});
Manual for uksort
use language construct. Before example 3.
I think what you need is to Asort categories and the use that sorted array in a foreach.
Asort($categories);
Foreach($categories as $key => $group){
$new[$key] =$people[$key];
}
Var_dump($new);
https://3v4l.org/kDAQW
Output:
array(3) {
["category_id_3"]=> array(3) {
[0]=> "Hannah"
[1]=> "Angie"
[2]=> "Raleigh"
}
["category_id_1"]=> array(3) {
[0]=> "Mark"
[1]=> "Jenny"
[2]=> "Andrew"
}
["category_id_2"]=>array(3) {
[0]=> "John"
[1]=> "Lewis"
[2]=> "Andrea"
}
}
Try this(tested and working):
asort($categories);
$sorted = array();
foreach ($categories as $key => $value)
$sorted[$key]=$people[$key];
A better shorter approach:(tested and working)
asort($categories);
$result = array_merge($categories,$people);
The second method takes advantage of the fact that array_merge function replace the values in the first array with those in the second one when keys are the same.
warning : The second approach will not work if the keys are numbers. Use only string keys with it. Furthermore if the categories array has entries without corresponding entries in the people array they will be copied to the result
To solve this problem we use array_replace :
asort($categories);
$result = array_replace($categories,$people);
Var_dump($result);// tested and working

array_combine not working (php)

I'm trying to create a list of users with the most sales and I'd like to find a way to combine two arrays.
$user_ids = sample_one();
$user_sales = sample_two();
var_dump on both sample functions:
array(2) {
[0]=> string(1) "1" // user ID
[3]=> string(1) "3"
}
array(2) {
[0]=> int(5) // User sales
[1]=> int(20)
}
In the end I'd like to combine these two arrays. Something like this:
$users = array (
array (
'id' => '1',
'sale' => '5'
)
array (
'id' => '3',
'sale' => '20'
),
)
I tried using array_combine( $user_ids, $user_sales ); but that didn't work. Any alternatives? Eventually I'll end up using it as
array_sort($users, 'sale', SORT_DESC)
I guess there is no such builtin method available you need to loop through your data and create your array
$data= array();
foreach($user_ids as $key=> $val){
if(isset($user_sales[$key])){
$data[] = array (
'id' => $val,
'sale' => $user_sales[$key]
);
}
}
Also make sure keys for both array should be same to map correct data for each user id
The correct function is array_merge($array1, $array2).
Fore more info read the documentation on array_merge.

PHP suppress part of array if duplicate

I have an array of database objects and I'm using foreach() to present the names and projects. Good, now the customer doesn't want duplicate names for when one person has multiple projects. This has to do with variable scope and this is my failed attempt to pull this stunt off. Here's a partial var_dump of the array of objects.
array [
0 => {
["lastName"]=>
string(1) "w"
["projectName"]=>
string(29) "Bone density scanner analysis"
}
1 => {
["lastName"]=>
string(1) "w"
["projectName"]=>
string(29) "analysis of foot"
}
]
What I want to end up with is:
array [
0 => {
["lastName"]=>
string(1) "w"
["projectName"]=>
string(29) "Bone density scanner analysis"
}
1 => {
["lastName"]=>
string(1) ""
["projectName"]=>
string(16) "analysis of foot"
}
]
Here's what I was thinking that doesn't seem to work:
function suppress_name($name){
global $string;
return ($name == $string) ? '' : $string;
}
function overall() {
//$result = database call to get objects
foreach ($result as $item) {
$string = $item->lastName;
$rows = array('Name' => suppress_name($item->lastName), 'project' => $item->projectName);
}
}
Researching I see several references to array_unique() which I use for a flattened array, but I can't see that it would help me here. OK, I thought I could make a function, like the above, to handle duplicates and use the $global but think I'm not grasping how to use globals in this instance. I'm happy to be pointed to a better way, or better search terms. Does this make sense?
Here is a possible approach to your solution, where we store the last names in a one dimensional array then check against it through each iteration of the array. If the lastName is in the array then set the value to ''.
Note the use of the reference (&).
<?php
$arrays = array(
array('lastName' => 'w', 'projectName' => 'Bone density scanner analysis'),
array('lastName' => 'w', 'projectName' => 'analysis of foot')
);
$last_names = array();
foreach($arrays as &$array){
if( in_array($array['lastName'],$last_names) ){
$array['lastName'] = '';
}else{
$last_names[] = $array['lastName'];
}
}
echo '<pre>',print_r($arrays),'</pre>';
It would be easier to work with nested arrays
array [
0 => {
["lastName"]=> string(1) "w"
["projects"]=> array [
0 => {
["projectName"] => string(29) "Bone density scanner analysis"
}
1 => {
["projectName"]=> string(16) "analysis of foot"
}
1 => {
["lastName"] => string(1) "x"
["projects"] => array [
0 => {
["projectName"] => string(16) "analysis of head"
} ]
}
]

Categories