Get certain elements of an array by its key - php

I'm sure there's a function for this:
What I have:
$myArray = array( 'foo' => 123, 'bar' => 456, 'lou' => 789, 'wuh' => 'xyz' );
$iNeed = array( 'foo', 'lou' );
How can I get the key value pairs that $iNeed:
$output = super_magic_function( $iNeed, $myArray );
// output should be array( 'foo' => 123, 'lou' => 789 );
How is that super_magic_function called (native php if possible)

$output = array_intersect_key($myArray, array_flip($iNeed));
If you need it as a function:
function super_magic_function($array, $required) {
return array_intersect_key($array, array_flip($required));
}
Output:
Array
(
[foo] => 123
[lou] => 789
)
Documentation: array_intersect_key(), array_flip()
Demo.

Related

PHP sum values from multidimensional array with using a for loop [duplicate]

This question already has answers here:
Sum values of multidimensional array by key without loop
(5 answers)
Closed 1 year ago.
I have a multidimensional array that looks like this..
$array = array (
'section1' => array (
'value' => 465,
'value2' => 744
),
'section2' => array (
'value' => 6544,
'value2' => 565
),
'section5' => array (
'value' => 345,
'value2' => 7465
)
);
I want to add all of the value2 together. I know I can do it with a for loop but is there a way to do it without doing this?
Could I use array_sum in combination with array_column to do this? The number of sections and the section name changes so I am not sure how to cater for this.
Use array_map to extract the required key's value, and then use array_sum.
$a = array (
'section1' => array (
'value' => 465,
'value2' => 744
),
'section2' => array (
'value' => 6544,
'value2' => 565
),
'section5' => array (
'value' => 345,
'value2' => 7465
)
);
echo array_sum(array_map('v',$a));
function v($v) {return $v['value2'];}
Teh Playground!
array_reduce variant:
$a = array (
'section1' => array (
'value' => 465,
'value2' => 744
),
'section2' => array (
'value' => 6544,
'value2' => 565
),
'section5' => array (
'value' => 345,
'value2' => 7465
)
);
print_r($a);
echo array_reduce($a, function($c, $s) { return $c + $s['value2']; }, 0);
// shorter with arrow functions
echo array_reduce($a, fn($c, $s) => $c + $s['value2'], 0);
Fiddle here.
You can use array_walk for example and passing $sum by reference.
<?php
$array = array (
'section1' => array (
'value' => 465,
'value2' => 744
),
'section2' => array (
'value' => 6544,
'value2' => 565
),
'section5' => array (
'value' => 345,
'value2' => 7465
)
);
$sum = 0;
array_walk($array, function($a) use (&$sum){
$sum2 += $a['value2'];
});
print_r($sum);
// 8774
I just used OOP to handle this
<?php
//Define class for calculating sum of value1 & value2
class _array {
//Define variables
private $sum_of_value = 0;
private $sum_of_value_2 = 0;
private $array = [];
//Appending object in list
public function append($title,$_value,$_value2)
{
$this->array[$title] = new obj($_value,$_value2);
$this->sum_of_value = $this->sum_of_value + $_value;
$this->sum_of_value_2 = $this->sum_of_value_2 + $_value2;
}
//Return list
public function getArray()
{
var_dump($this->array);
}
//Return sum of value
public function getSumOfValue()
{
echo $this->sum_of_value;
}
//Return sum of value2
public function getSumOfValue2()
{
echo $this->sum_of_value_2;
}
}
//Definiton of our object
class obj{
public $value;
public $value2;
function __construct($value,$value2) {
$this->value = $value;
$this->value2 = $value2;
}
}
//Enter values
$array = new _array();
$array->append('section1',465,744);
$array->append('section2',6544,565);
$array->append('section5',345,7465);
//Get array
$array->getArray();
//Get sum of value & sum of value 2
$array->getSumOfValue();
echo '<br>';
$array->getSumOfValue2();
?>

unset() in multidimensional array check if key exists first

My array:
$array = array(
'test' => 'hello',
'something' => array(
'sub1' => 'foo'
)
);
I'd like to use:
if(array_key_exists('sub1', $array['something'])
{
unset($array['something']['sub1'];
}
The unset part works, but the if statement returns false while the sub1 item is definitely there. Why is this?
I think you need to reformat your code a little. However, here is the formatted code,
$arr = [
'test' => 'hello',
'something' => [
'sub1' => 'foo'
]
];
if(
is_array($arr['something']) &&
array_key_exists('sub1', $arr['something'])
)
{
unset($arr['something']['sub1']);
}
print_r($arr);
and I am getting following result,
Array
(
[test] => hello
[something] => Array
(
)
)
Can you elaborate on what is it that you want to do ??

What is a better way to replace IDs in an array with their value counterpart?

I have the following array that includes id:
[Key1] => 1
[Key2] => 2, 3
I would like to replace these ids by their respective name from this second array:
[0] => Array
(
[ID] => 1
[Name] => Name1
)
[1] => Array
(
[ID] => 2
[Name] => Name2
)
[2] => Array
(
[ID] => 3
[Name] => Name3
The desired output:
[Key1] => Name1
[Key2] => Name2, Name3
I have the following code which works but I know this is not the right way. If anybody could let me know what would be a better way to achieve this, it would be greatly appreciated.
What my code looks like:
$var1 = explode(", ", $array1["Key1"]); // No need to explode in this example but "Key1" sometimes includes more than 1 ID
$var2 = explode(", ", $array1["Key2"]);
$array1["Key1"] = $var1 ; // This row is for the new array generated from "explode" to be a sub-array
$array1["Key2"] = $var2 ; // Same
for ($i = 0; $i < 83; $i++){
if($array1["Key1"][0] == $array2[$i]["ID"]){
$array1["Key1"][0] = $array2[$i]["Name"];
}
if($array1["Key1"][1] == $array2[$i]["ID"]){
$array1["Key1"][1] = $array2[$i]["Name"];
}
// (etc)
if($array1["Key2"][0] == $array2[$i]["ID"]){
$array1["Key2"][0] = $array2[$i]["Name"];
}
if($array1["Key2"][1] == $array2[$i]["ID"]){
$array1["Key2"][1] = $array2[$i]["Name"];
}
// (etc)
}
$var1 = implode(", ", $array1["Key1"]);
$var2 = implode(", ", $array1["Key2"]);
$array1["Key1"] = $var1 ;
$array1["Key2"] = $var2 ;
Just extract the ID and Name into a single-dimension and use it as search and replace parameters. We need to modify the IDs to search for and turn them into a pattern /\b$v\b/ where \b is a word boundary, so that 1 won't replace the 1 in 164 for example:
$replace = array_column($array2, 'Name', 'ID');
$search = array_map(function($v) { return "/\b$v\b/"; }, array_keys($replace));
$array1 = preg_replace($search, $replace, $array1);
You need to nest some loops. Here is a sample that should work:
//Processing Array
$arrayOne = array(
"Key1" => "1",
"Key2" => "2, 3");
//Lookup Array
$arrayTwo = array(
array(
"ID" => "1",
"Name" => "Name1"),
array(
"ID" => "2",
"Name" => "Name2"),
array(
"ID" => "3",
"Name" => "Name3"));
var_dump($arrayOne);
//Loop through all values in our original array
foreach($arrayOne as &$arrValue) {
//Split the value in the original array into another temporary array
//if there are multiple values.
$valueArray = explode(", ", $arrValue);
$outputArray = array();
foreach($valueArray as &$myValue) {
//Now do a lookup to replace each value
foreach($arrayTwo as &$lookupValue) {
//Find a match
if($myValue==$lookupValue["ID"]) {
$myValue = $lookupValue["Name"];
//We found the value we want, so let's break out of this loop
break;
}
}
//Append the value
array_push($outputArray, $myValue);
}
//Convert back to string
$arrValue= implode(", ", $outputArray);
}
var_dump($arrayOne);
There are improvements you could possibly make to this code if your incoming data was always sorted, but I imagine that is just the case for your sample above.
I have an approach to do this. You can make a try if you wish see here at:- https://eval.in/839823. I am using array_column to map the key=>value pair and then simple used foreach.
<?php
$main = ['Key1' => 1,'Key2' => '2, 3'];
$match = [
[
'ID' => 1,
'Name' => 'Name1'
],
[
'ID' => 2,
'Name' => 'Name2'
],
[
'ID' => 3,
'Name' => 'Name3'
]
];
$final_array=[];
$mapped = array_column($match, 'Name', 'ID');
foreach($main as $k=>$v){
$r = explode(',',$v);
if(count($r)>1){
$final_array[$k] = $mapped[$r[0]]. ", ".$mapped[intval($r[1])];
}else{
$final_array[$k] = $mapped[$r[0]];
}
}
print '<pre>';
//print_r($mapped);
print_r($final_array);
print '</pre>';
Output :
Array
(
[Key1] => Name1
[Key2] => Name2,Name3
)
Edit : As per comment of Josh Maag,
My code will only work if he only has a maximum of 2 values in Key2.
If Key3 contains "4,5,6" this code will leave the 6 untouched.
<?php
$main = ['Key1' => 1,'Key2' => '2,3','Key3' => '4,5,6'];
$match = [
[
'ID' => 1,
'Name' => 'Name1'
],
[
'ID' => 2,
'Name' => 'Name2'
],
[
'ID' => 3,
'Name' => 'Name3'
],
[
'ID' => 4,
'Name' => 'Name4'
],
[
'ID' => 5,
'Name' => 'Name5'
],
[
'ID' => 6,
'Name' => 'Name6'
]
];
$final_array=[];
$mapped = array_column($match, 'Name', 'ID');
foreach($main as $k=>$v){
$r = explode(',',$v);
if(count($r)>1){
$final_array[$k] = implode(',',array_map(function($key) use ($mapped){ return $mapped[$key]; }, array_values($r)));
}else{
$final_array[$k] = $mapped[$r[0]];
}
}
print '<pre>';
print_r($mapped);
print_r($final_array);
print '</pre>';
?>
See demo See here https://eval.in/839939
The core function that should be used for this task is preg_replace_callback(). Why? Because it is uniquely qualified to handle this operation in a single function call. It seems a tragedy to not use php functions for their designed purpose.
Beyond preg_replace_callback(), only array_column() is needed to prepare the $array2 data as a simple lookup array.
Code: (Demo)
$array1=["Key1"=>"1","Key2"=>"22, 4, 123"];
$array2=[["ID"=>"1","Name"=>"Name1"],["ID"=>"22","Name"=>"Name22"],["ID"=>"123","Name"=>"Name123"]];
$lookup=array_column($array2,'Name','ID'); // generate array: keys = IDs, vals = Names
$result=preg_replace_callback('/\d+/',function($m)use($lookup){return isset($lookup[$m[0]])?$lookup[$m[0]]:"*{$m[0]}*";},$array1);
var_export($result);
Output:
array (
'Key1' => 'Name1',
'Key2' => 'Name22, **4**, Name123',
)
There is no need to run any preparations (excluding $lookup) using additional loops or function calls.
This pattern will match all full ID numbers from each element in $array1 and process them individual. Each numeric match is sent to the anonymous callback function to receive its customized replacement string -- delivered by the $lookup data.
As an additional consideration, I have included an asterisk-wrapped replacement when an ID is not found in $lookup.

Effective and elegant way to get an item from array

For example, i've got an array like this:
$a = array(
0 => array(
'foo' => 42
),
1 => array(
'foo' => 143
),
2 => array(
'foo' => 4
)
);
And i need to get an element with a maximum value in 'foo'. Current code is this:
$foos = array_map(function($v) {
return $v['foo'];
}, $a);
$keys = array_keys($foos, max($foos));
$winner = $a[$keys[0]];
print_r($winner);
Which is a scary thing.
You can try with:
$input = array(
array('foo' => 42),
array('foo' => 143),
array('foo' => 4),
);
$output = array_reduce($input, function($a, $b) {
return $a['foo'] > $b['foo'] ? $a : $b;
});
Output:
array (size=1)
'foo' => int 143
Most elegant?
$maxValue = max($a);
http://www.php.net/manual/en/function.max.php
Works even with multi-dimensional:
<?php
$a = array(
0 => array(
'foo' => 42
),
1 => array(
'foo' => 143
),
2 => array(
'foo' => 4
)
);
$maxValue = max($a);
print_r($maxValue["foo"]);
echo $maxValue["foo"];
Output with echo 143.
Output with print_r() Array ( [foo] => 143 )
Just run the foreach yourself. Readable and easy.
$highest_foo = PHP_INT_MIN;
$result = null;
foreach ($a as $key=>$foo) {
if ($foo['foo'] > $highest_foo) {
$result = $a[$key];
$highest_foo = $foo['foo'];
}
}
print_r($result);
$array = array(
0 => array(
'foo' => 42
),
1 => array(
'foo' => 143
),
2 => array(
'foo' => 4
)
);
$maxs = array_keys($array, max($array));
print_r(max($array));//Highest value
print_r($maxs);//Key of hishest value

function calling itself

again with another problem.
public function __construct() {
$_GET = $this->clean($_GET);
$_POST = $this->clean($_POST);
...
}
public function clean($data) {
if (is_array($data)) {
foreach ($data as $key => $value) {
unset($data[$key]);
$data[$this->clean($key)] = $this->clean($value);
}
} else {
$data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
}
return $data;
}
i dont understand why $data[$this->clean($key)] = $this->clean($value); is calling its own function. what is the point of doing this? the advantages
thanks,
daniel
It's a technique called recursion. This particular function descends into the structure until it is dealing with very simple data and sanitizes it all.
Given this:
$arr = array (
'<foo' => array(
'bat' => 'OMGWTFBBQ!!><!?!'
),
'bar' => 'baz'
);
It would start:
is arr an array?
is <foo an array? (no)
<foo becomes <foo
<foo used as a key
is the value of <foo an array? (yes)
Is bat an array? (no)
bat remains as is (still has htmlspecialchars called, but it does not change anything))
Is 'OMGWTFBBQ!!><!?!' an array (no)?
'OMGWTFBBQ!!><!?!' is converted to 'OMGWTFBBQ!!><!?!'
'OMGWTFBBQ!!><!?!' is used for the value for bat.
Is 'bar' an array? (no)
bar returned as is (like bat above)
Is baz an array? (no)
baz returned as is.
You can think of it this way
$arr = array (
'<foo' => array(
'bat' => 'OMGWTFBBQ!!><!?!'
),
'bar' => 'baz'
);
///////////////////////////////////////////
array (
clean('<foo') => array(
'bat' => 'OMGWTFBBQ!!><!?!'
),
'bar' => 'baz'
);
///////////////////////////////////////////
array (
'<foo' => clean( array(
'bat' => 'OMGWTFBBQ!!><!?!'
)),
'bar' => 'baz'
);
///////////////////////////////////////////
array (
'<foo' => array(
clean( 'bat' ) => 'OMGWTFBBQ!!><!?!'
)),
'bar' => 'baz'
);
///////////////////////////////////////////
array (
'<foo' => array(
'bat' => clean( 'OMGWTFBBQ!!><!?!' )
)),
'bar' => 'baz'
);
///////////////////////////////////////////
array (
'<foo' => array(
'bat' => 'OMGWTFBBQ!!><!?!'
)),
clean( 'bar' ) => 'baz'
);
///////////////////////////////////////////
array (
'<foo' => array(
'bat' => 'OMGWTFBBQ!!><!?!'
)),
'bar' => clean( 'baz' )
);
///////////////////////////////////////////
return array (
'<foo' => array(
'bat' => 'OMGWTFBBQ!!><!?!'
)),
'bar' => 'baz'
);
clean function uses htmlspecialchars to clean html chars from string. But if $data is an array it calls itself for cleaning all of its keys and values. This is why clean is recursive.
The advantage of this approach is clean function works for string and array transparently.
It's called recursion.
In your example the $_GET and $_POST arrays may contain elements which are also arrays which themselves can contain arrays (ad infinitum). So you don't know how many sub-arrays you will have to clean up.
To solve this problem the function clean is written in a manner that it calls itself when it occurs a "sub array" while cleaning the current array. It's like a loop just for nested data structures.

Categories