I'm trying to remove duplicated entries where value and type are both equal on a multidimensional associative array, but only using recursion and without array_unique. All keys are associative.
I tried this, and I'm getting the same result as the main array. My logic seems to fail me at this late hour.
function rmDuplicates(&$array) {
$uniqueArray = array();
foreach($array as $k=>$v) {
if (is_array($v)) {
$uniqueArray[$k] = rmDuplicates($v);
} else {
if (!in_array($v, $uniqueArray)) {
$uniqueArray[] = $v;
}
}
}
return $uniqueArray;
}
Related
$arr1 = array('foo'=>array('green'=>10, 'flowers'=>20), 'bar'=>20);
$arr2 = array('red'=>'roses', 'blue'=>'sky', foo=>array('flowers'=>15), 'bar'=>array('demo'=>'asdf'));
Desired result of the merge:
array('foo'=>array('green'=>10, 'flowers'=>15), 'bar'=>array('demo'=>'asdf'));
I have written a recursive function for this purpose, but I wonder if there is a more elegant way in PHP to achieve this.
This is my function:
function array_overwrite_recursive($arr1, $arr2) {
foreach($arr1 As $k=>$v) {
if(is_array($arr1[$k])) {
$arr1[$k] = array_overwrite_recursive($arr1[$k], $arr2[$k]);
} else {
if(isset($arr2[$k])) $arr1[$k]=$arr2[$k];
}
}
return $arr1;
}
on http://php.net/manual/en/function.in-array.php - if you scroll down it gives a function to determine if a string is inside of a query in a multidimensional array. "If you found yourself in need of a multidimensional array in_array like function you can use the one below. Works in a fair amount of time"
Here's original code(working):
function in_multiarray($elem, $array)
{
$top = sizeof($array) - 1;
$bottom = 0;
while($bottom <= $top)
{
if($array[$bottom] == $elem)
return true;
else
if(is_array($array[$bottom]))
if(in_multiarray($elem, ($array[$bottom])))
return true;
$bottom++;
}
return false;
}
What I'm trying to do is instead of returning 'true' or 'false' - i'd like to return the ROW #. So my initial thought was to simply replace 'return true' with 'return $bottom; however it isn't returning the record number.
Modified Function (not working);
function in_multiarray($elem, $array)
{
$top = sizeof($array) - 1;
$bottom = 0;
while($bottom <= $top)
{
if($array[$bottom] == $elem)
return $bottom;
else
if(is_array($array[$bottom]))
if(in_multiarray($elem, ($array[$bottom])))
return $bottom;
$bottom++;
}
return false;
}
Does anyone have an idea how to modify this function to return the ROW number that contains the match?
Here's a sample of the array...
$sample = array
array ("oldpage1.php","newpage1.php"),
array ("oldpage2.php","newpage2.php"),
array ("oldpage3.php","newpage3.php"),
array ("oldpage4.php","newpage4.php"),
array ("oldpage5.php","newpage5.php")
etc.
);
$row = in_multiarray($input, $sample);
Therefore if we know the row # we can fetch the new page with a simple
$newpage=$sample[$row][1]
Thanks!
It's worth noting that a function like in_array is intended to tell you whether or not a value exists inside of an array. What you're looking for seems to be a lot closer to something like array_search, which is designed to actually provide you with the key that points to a given value in the array.
However, because you're using a multi-dimensional array what you're actually looking for is the key that points to the array that contains the value. Hence we can divide and conquer this problem with two simple steps.
Map
Filter
The first step is to map a function in_array to every element in the first array (which is just another array). This will tell us which elements of the primary array contain an array that contains the value we're searching for.
$result = array_map(function($arr) use($search) {
return in_array($search, $arr, true);
}, $arr, [$searchValue]);
The second step is to then return the keys to those arrays (i.e. filter the result).
$keys = array_keys(array_filter($result));
Now you have all the keys of any matching items. If you want to apply as just one custom filter that specifies exactly where in the subarray to look, you could also do it like this.
$search = "oldpage2.php";
$sample = [
["oldpage1.php","newpage1.php"],
["oldpage2.php","newpage2.php"],
["oldpage3.php","newpage3.php"],
["oldpage4.php","newpage4.php"],
["oldpage5.php","newpage5.php"],
];
$keys = array_keys(array_filter($sample, function($arr) use($search) {
return $arr[0] === $search;
}));
var_dump($keys);
And you get...
array(1) {
[0]=>
int(1)
}
So now you know that "oldpage2.php" is in row 1 in $sample[1][0] which means you can do this to get the results out of the array.
foreach($keys as $key) {
echo "{$sample[$key][0]} maps to {$sample[$key][1]}\n";
}
Giving you
oldpage2.php maps to newpage2.php
If you want to return only the first result you could do that as well with a function like this using similar approach.
function getFirstMatch($search, Array $arr) {
foreach($arr as $key => $value) {
if ($value[0] === $search) {
return $value[1];
}
}
}
echo getFirstMatch("oldpage4.php", $sample); // newpage4.php
The Better Alternative
Of course, the better approach is to actually use the oldpage names as the actual keys of the array rather than do this expensive search through the array, because array lookup by key in PHP is just an O(1) operation, whereas this needle/haystack approach is O(N).
So we turn your $samples array into something like this and the search no longer requires any functions...
$samples = [
"oldpage1.php" => "newpage1.php",
"oldpage2.php" => "newpage2.php",
"oldpage3.php" => "newpage3.php",
"oldpage4.php" => "newpage4.php",
"oldpage5.php" => "newpage5.php",
];
Now you can just do something like $newpage = $samples[$search] and you get exactly what you're looking for. So echo $samples["oldpage2.php"] gives you "newpage2.php" directly without the intermediary step of searching through each array.
You can use the following code to get the full path to the value:
function in_multiarray($elem, $array, &$result)
{
$top = sizeof($array) - 1;
$bottom = 0;
while($bottom <= $top)
{
if($array[$bottom] == $elem) {
array_unshift($result, $bottom);
return true;
}
else {
if(is_array($array[$bottom])) {
if(in_multiarray($elem, $array[$bottom], $result)) {
array_unshift($result, $bottom);
return true;
}
}
}
$bottom++;
}
array_shift($result);
return false;
}
$sample = array(
array ("oldpage1.php","newpage1.php"),
array ("oldpage2.php","newpage2.php"),
array ("oldpage3.php","newpage3.php"),
array ("oldpage4.php","newpage4.php"),
array ("oldpage5.php","newpage5.php")
);
$input = "newpage5.php";
$result = [];
in_multiarray($input, $sample, $result);
print_r($result);
Path is stored in $result;
I've written the below function, it takes in a 2 dimensional array and return the number of times a key occurs, BUT it feels like i may be reinventing the wheel here, is there an easy way?
function countKeys($array, $key)
{
$results = array();
foreach($array as $row)
{
if (array_key_exists($row[$key], $results))
{
$results[$row[$key]] += 1;
}
else
{
$results[$row[$key]] = 1;
}
}
return $results;
}
To count the keys in a two dimensional array with a search I would do this -
function countKeys($array,$search){
$key_count = array(); // new array
foreach($array as $record) {
$keys = array_keys($record);
foreach($keys as $key){
if($key == $search){ // check against the search term
array_push($key_count, $key); // add the key to the new array
}
}
}
return count($key_count); // just count the new array
}
echo countKeys($records, 'last_name');
EXAMPLE
array_keys()
count()
For a 2 dimensional array try:
$result = count(array_column($array, $key));
PHP >= 5.5.0 needed for array_column() or use the PHP Implementation of array_column()
Just use count() function like:
count($array);
see: http://php.net/manual/pt_BR/function.count.php
You can use this function to count arrays variable as well.
Hope it helps you.
I am writing a shopping cart session handler class and I find myself repeating this certain chunk of code which searches a multidimensional associative array for a value match.
foreach($_SESSION['cart'] as $k => $v){
if($v['productID'] == $productID){
$key = $k;
$this->found = true;
}
}
I am repeating this when trying to match different values in the array.
Would there be an easy to to create a method whereby I pass the key to search and the value. (Sounds simple now I read that back but for some reason have had no luck)
Sounds like you want something like this:
function findKey(array $array, $wantedKey, $match) {
foreach ($array as $key => $value){
if ($value[$wantedKey] == $match) {
return $key;
}
}
}
Now you can do:
$key = findKey($_SESSION['cart'], 'productID', $productID);
if ($key === null) {
// no match in the cart
} else {
// there was a match
}
suppose I have a multidimensional array structure:
array(parent)
array
array
array(parent)
array(parent)
...some key I'm looking for....
array
array
array
array
array
array
array
I iterate over it recursively to find an array that contains some key I'm looking for - this is no problem.
But then I need to walk up the tree and add additional key to all parents (marked by parent). I can't wrap my head around it. I can easily walk down the tree recursively but I can't figure out how to walk up. Can someone point me to the right direction?
This is an example that I've just wrote just to get the idea.
NOTE that this will break execution on the first occurrence of the matched value.
codepad link
$arr = array(
array('a','b','c','d'),
array(61,62,63,64,65),
array('e','f','g','h'),
array(6,7,8,9),
array(1,2,array(1,2,3,4,5,6,7,8),4,5,6,7,8),
array('i','j','k','l','m'),
);
function array_walkup( $desired_value, array $array, array $keys=array() ) {
if (in_array($desired_value, $array)) {
array_push($keys, array_search($desired_value, $array));
return $keys;
}
foreach($array as $key => $value) {
if (is_array($value)) {
$k = $keys;
$k[] = $key;
if ($find = array_walkup( $desired_value, $value, $k )) {
return $find;
}
}
}
return false;
}
$keys = array_walkup(3, $arr);
echo "3 has been found in \$arr[".implode('][', $keys)."]";
You can use something along these lines in a class:
private $valueFound;
public function recurse($item)
{
if ($item['special_field'] === 'value you are looking for')
{
$this->valueFound = $item['other_field'];
return;
}
if (isset($item['child'])
{
recurse($item['child']);
}
// Use tail-recursion.
// You are at this point past all recursion and are heading back up the tree.
$item['field_to_set'] = $this->valueFound;
}