Reducing multidimensional array - php

I have the following multidimensional array:
Array
(
[0] => Array
(
[area] => 5
[estante] => 5
[anaquel] => 5
[no_caja] => 5
[id_tipo] => 3
[nombre_tipo] => Administrativo
)
[1] => Array
(
[area] => 5
[estante] => 5
[anaquel] => 5
[no_caja] => 5
[id_tipo] => 1
[nombre_tipo] => Copiador
)
[2] => Array
(
[area] => 5
[estante] => 5
[anaquel] => 5
[no_caja] => 5
[id_tipo] => 2
[nombre_tipo] => Judicial
)
)
and I want to reduce it by having all the different values (intersection) between them. The dimension of the array may change (I'm retrieving the info from a database). I have thought in using functions like array_reduce and array_intersect, but I have the problem that they work only with one-dimension arrays and I can't find the way to pass an indefinite (not previous known) number of parameters to these function. I'd like to have an output like this:
Array([0]=>Copiador, [1]=>Administrativo, [2]=>Judicial).
How can I do this?
Thanks in advance.

$arr=array(
array (
'area' => 5 ,
'estante' => 5 ,
'anaquel' => 5,
'no_caja' => 5,
'id_tipo' => 3,
'nombre_tipo' => 'Administrativo'),
array (//etc.
)
);
$fn=function(array $a, $k){
if(array_key_exists($k,$a)) return $a[$k];
};
$b=array_map($fn,$arr,array_fill(0,count($arr),'nombre_tipo'));
print_r($b);
/*
Array
(
[0] => Administrativo
[1] => Copiador
[2] => Judicial
)
*/

$reduced = array();
foreach ($oldarray as $value) {
$reduced[] = $value['nombre_tipo'];
}
Although, a better solution may be to just modify your SQL query so you get the correct data to begin with.
Note: you can also do it with array_reduce, but I personally prefer the method above.
$reduced = array_reduce($oldarray,
function($a, $b) { $a[] = $b['nombre_tipo']; return $a; },
array()
);

This task is exactly what array_column() is for -- extracting columnar data.
Call this:
var_export(array_column($your_array, 'nombre_tipo'));
This will output your desired three-element array. ...I don't understand the sorting in your desired output.

Seems like you want array_map
$newArr = array_map(function($a) {
return $a['nombre_tipo'];
}, $oldArr);
var_dump($newArr);

Related

Why does search for matching value in multi dimensional array not return a result? [duplicate]

This question already has answers here:
Reference: What is variable scope, which variables are accessible from where and what are "undefined variable" errors?
(3 answers)
Closed 4 years ago.
I have a multi dimensional array where I want to retrieve the key of each element that matches '116234':
$test = Array
(
[8708] => Array
(
[ref_id] => 93939
)
[8709] => Array
(
[ref_id] => 116234
)
[8710] => Array
(
[ref_id] => 116234
)
)
In that case the desired keys are: 8709, 8710.
Somehow the filter function does not work:
$data['attr'][8] = '116234';
$filtered = array_filter($test, function($v) { return $v['ref_id'] == $data['attr'][8]; });
print_r($filtered);
response:
Array
(
)
According to an answer within another question at SO this should work.
Is this somehow wrong, or does the filter function rely on a certain PHP version?
The code you provided seems to be working, however, if you just want the keys of the associative array as the output you can use array_keys to get the keys of your filtered result.
$test = Array(
8708 => Array('ref_id' => 93939),
8709 => Array('ref_id' => 116234),
8710 => Array('ref_id' => 116234)
);
$filtered = array_filter($test, function($v) { return $v['ref_id'] == '116234'; });
print_r(array_keys($filtered)); // array_keys to get the keys from filtered
Output:
Array ( [0] => 8709 [1] => 8710 )
EDIT: The issue that you're having with your updated question is that $test cannot be seen within filter's anonymous function, and so you need to use the use keyword to give access to it. Read more about use here.
Working code:
$test = Array(
8708 => Array('ref_id' => 93939),
8709 => Array('ref_id' => 116234),
8710 => Array('ref_id' => 116234)
);
$data['attr'][8] = '116234';
$filtered = array_filter($test, function($v) use (&$data) {
return $v['ref_id'] == $data['attr'][8];
});
print_r(array_keys($filtered));
Output:
Array ( [0] => 8709 [1] => 8710 )
Your code doesn't work because $data is not in scope in your anonymous function. If you had PHP error reporting enabled you would have seen 3 error messages like this:
Notice: Undefined variable: data in /in/RNpEd on line nnn
You need to rewrite your code like this (note the use ($data) in the definition of the anonymous function):
$test = array('8708' => array('ref_id' => '93939'), '8709' => array('ref_id' => '116234'), '8710' => array('ref_id' => '116234'));
$data['attr'][8] = '116234';
$filtered = array_filter($test, function($v) use($data) { return $v['ref_id'] == $data['attr'][8]; });
print_r($filtered);
Output:
Array (
[8709] => Array (
[ref_id] => 116234
)
[8710] => Array (
[ref_id] => 116234
)
)
Demo on 3v4l.org
I would rather filter it anther way such as this:
$a = array (
8708 =>
array (
'ref_id' => 93939
),
8709 =>
array (
'ref_id' => 116234
),
8710 =>
array (
'ref_id' => 116234
)
);
$data['attr'][8] = '116234';
$filtered = array_intersect(array_combine(array_keys($a),array_column($a,'ref_id')),[$data['attr'][8]]);
print_r($filtered);
Output
Array
(
[8709] => 116234
[8710] => 116234
)
Sandbox
But I am probably just being weird.
Oh and as a Bonus this also makes it possible to match multiple values, where the filter method was limited to one (use ($data) and dependent condition). The last array [$data['attr'][8]] can have multiple values to match with. In this case it's [116234], but it could just as easily be this [116234,93939] which would return the full array.
To explain how it works:
$filtered = array_intersect(
array_combine(
array_keys($a),
array_column($a, 'ref_id')
),
[$data['attr'][8]]
);
Will work our way through it:
array_column($a, 'ref_id')
//Output
Array
(
[0] => 93939
[1] => 116234
[2] => 116234
)
This flattens out our array, to make it easier to work with. Next we combine that with the array keys of the original array:
array_keys($a)
//Output
Array
(
[0] => 8708
[1] => 8709
[2] => 8710
)
This is an important step, because both arrays are the same size, same order, we can combine them and basically un-nest the ref_id column.
array_combine(
array_keys($a),
array_column($a, 'ref_id')
),
//Output
Array
(
[8708] => 93939
[8709] => 116234
[8710] => 116234
)
Now it's a trivial matter of using array intersect to retrieve the parts we want.
If you wanted to retrieve just the ID's such as this output:
Array
(
[0] => 8709
[1] => 8710
)
This can be done by wrapping the whole thing in another array keys, like this:
$filtered = array_keys(array_intersect(array_combine(array_keys($a),array_column($a,'ref_id')),[$data['attr'][8]]));
And the last parting gift I will give is this:
function filter_mutidimensional(array $array, $match){
if(!is_array($match)) $match = [$match];
return array_keys(array_intersect(array_combine(array_keys($array),array_column($array,'ref_id')),$match));
}
//which you can call like
filter_mutidimensional($a,$data['attr'][8]);
//or
filter_mutidimensional($a,[$data['attr'][8]]);
//or
filter_mutidimensional($a,[$data['attr'][8],93939]);
Hope that all makes sense!

How to sort associative array?

I have associative array. On print_f($array_name), I got this
Array (
[0] => Array (
[teamid] => abc
[distance] => 1.25
)
[1] => Array (
[teamid] => xyz
[distance] => 0.25
)
)
This is that array which I want to sort according to distance. eg, This should be look like this after sorting,
Array (
[0] => Array (
[teamid] => xyz
[distance] => 0.25
)
[1] => Array (
[teamid] => abc
[distance] => 1.25
)
)
If anyone know answer then please explain or suggest me link from where I can understand from beginning. Thank You.
Here is what you need to do.
$a = array(array( 'teamid' => 'abc', 'distance' => 1.25 ), array( 'teamid' => 'xyz', 'distance' => 0.25 ));
$distance = array();
foreach ($a as $key => $row)
{
$distance[$key] = $row['distance'];
}
array_multisort($distance, SORT_ASC, $a);
print_r($a);
This outputs
Array
(
[0] => Array
(
[teamid] => xyz
[distance] => 0.25
)
[1] => Array
(
[teamid] => abc
[distance] => 1.25
)
)
source Example #3 Sorting database results
DEMO
Edit
as per Mike's comment,
here are two answers,
one tells that on single array you should use usort(as Mike's answer) and array_multisort is used to compare elements from different arrays (or sub-arrays) at the same time.
in the other answer, as Mike wants some bench marking
usort() is more concise and doesn't require extracting a column array to feed to array_multisort(). (It also does less than array_multisort.)
However, when I repeatedly tested it today on arrays of 20,000 and
10,000 representative data rows, usort() was 7-15x slower than
array_multisort() when the column was random values of type int and
the column was pre-extracted. That is as one might expect, since for
every comparison you're comparing an entire php function call to
optimized intrinsic code.
more about bench marking notes, read full answer
$array = array(
array('teamid' => 'a', 'distance' => 1.25),
array('teamid' => 'b', 'distance' => 0.25),
array('teamid' => 'c', 'distance' => 2.5),
array('teamid' => 'd', 'distance' => 0.75),
);
function cmp($a, $b)
{
if ($a['distance'] == $b['distance']) return 0;
return ($a['distance'] < $b['distance']) ? -1 : 1;
}
usort($array, "cmp");
More info: http://php.net/usort

Array_Unique filtering

I have an multidimensional array:
Array
(
[0] => Array
(
[Id] => 1
[MTime_Id] => 1
[MName] => Breakfast
[DName] => Other Cereals
[IName] =>
[Date] => 2013-02-05
)
[1] => Array
(
[Id] => 1
[MTime_Id] => 1
[MName] => Breakfast
[DName] => Porridge
[IName] => Oats,Milk,Sugar
[Date] => 2013-02-06
)
[2] => Array
(
[Id] => 1
[MTime_Id] => 1
[MName] => Breakfast
[DName] => Porridge
[IName] => Oats,Milk,Sugar,Oats,Milk,Sugar
[Date] => 2013-02-05
)
)
And I am trying to use array unique to filter this
[IName] => Oats,Milk,Sugar,Oats,Milk,Sugar
I am having no luck. How can I filter the duplicates?
Cheers.
If you filter input and therefore don't have extra spaces in IName field, you can use something as simple as this for filtering:
$array[2]['IName'] = implode(',', array_unique(explode(',', $array[2]['IName'])));
The problem is that you habe in array two Oats,Milk,Sugar as element of IName, in array three you have Oats,Milk,Sugar,Oats,Milk,Sugar. This is not the same!
"Oats,Milk,Sugar"=="Oats,Milk,Sugar,Oats,Milk,Sugar" (or "Oats,Milk,Sugar".equals("Oats,Milk,Sugar,Oats,Milk,Sugar")) is false.
If you want to have it unique you have to explode the single results and then do a unique on it or you have to store the single values in seperate fields...
BTW: Here is a link how to remove duplicates from a multi dimensional array How to remove duplicate values from a multi-dimensional array in PHP
I am not sure if a function exists for that, here is a simple solution,
you can loop the array, and get the result of each value, then explode result, and insert it into an array.
then use the array_unique function.
try this:
$result = array();
foreach($arrays as $array)
{
$tmp = $array['IName'];
$tmp2 = explode(',',$tmp);
foreach ($tmp2 as $t)
{
$result[]=$t;
}
}
$array_unique = array_unique($result);

PHP: Sorting Multi-Array Result [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I sort a multidimensional array in php
Array ( [0] => Array (
[card_name] => CardA
[str] => 10
[def] => 10
[desc] => - Recover 150 points of vitality
- Attack twice"
[qty] => 5
)
[1] => Array (
[card_name] => CardD
[str] => 40
[def] => 40
[desc] => - Investigate enemy's weakpoint
[qty] => 3
)
[2] => Array ( [card_name] => CardG
[str] => 35
[def] => 20
[desc] =>
[qty] => 1
)
[3] => Array (
[card_name] => CardH
[str] => 25
[def] => 30
[desc] =>
[qty] => 1
)
[4] => Array (
[card_name] => CardI
[str] => 15
[def] => 40
[desc] => - Enhance strength
[qty] => 1
)
[5] => Array (
[card_name] => CardJ
[str] => 5
[def] => 50
[desc] => - Make silence
[qty] => 3
)
)
I have a simple question about sorting arrays. I just want to sort the array in either by str or def in either asc or desc. The examples in the php.net is a bit confusing and I was wondering if anyone can solve this small dilemma.
I know I should be using array_multi_sort for this.
Thanks.
Use the usort function. It will be something like this in your case :
function compare($valueA, $valueB) {
if ($valueA['str'] > $valueb['str']) {
return 1;
} else if ($valueA['str'] < $valueb['str']) {
return -1;
}
return 0;
}
usort($yourArray, "compare");
Try php usort - http://www.php.net/manual/en/function.usort.php
I've not tried and run the code but it'll be something below:
function cmp($a, $b)
{
return strcmp($a['def'],$b['def'])
}
$a = yourArray[];
usort($a, "cmp");
This will iterate through each element and pass the array element as a parameter and will use your custom function to sort.
usort() and strnatcmp() is your solution:
<?php
function build_sorter($key) {
return function ($a, $b) use ($key) {
return strnatcmp($a[$key], $b[$key]);
};
}
usort($array, build_sorter('def'));
print_r($array);
?>
It will sort all arrays by your defined key.
Array multisort requires you to build an array holding the values of the keys you want to sort by to do what you want, but with the same first dimension keys of the original array.
Thus if you make an array which holds 0 => 10, 1 => 5... etc where those are the values for str or def for keys 0 and 1, then you can do
foreach($originalArray as $key => $record) {
$keyValuesArray[$key] = $record['str'];
}
array_multisort($keyvaluesArray, SORT_ASC, $originalArray);
And original array would be modified to be sorted.
As for what you should be doing, I don't think array multisort is "the way" to do it, but is not a terrible way of doing it. Other solutions might be slightly more efficient.

Add array to an array with the same indexes not being merged [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Combine Two Arrays with numerical keys without overwriting the old keys
OK guys, was searching about this one with no luck - it always points only to array_merge or array_push or array_combine functions which are useless for my purpose.
Here are two arrays (number indexed):
Array (
[0] => 12345
[1] => "asdvsdfsasdfsdf"
[2] => "sdgvsdfgsdfbsdf"
)
Array (
[0] => 25485
[1] => "tyjfhgdfsasdfsdf"
[2] => "mojsbnvgsdfbsdf"
)
and I need to create one "joined" (unioned) array, so it will look like:
Array (
[0] => 12345
[1] => "asdvsdfsasdfsdf"
[2] => "sdgvsdfgsdfbsdf"
[3] => 25485
[4] => "tyjfhgdfsasdfsdf"
[5] => "mojsbnvgsdfbsdf"
)
As I found nothing on this problem I tried by myself ($arr1 and $arr2 are the two small arrays):
$result_array = $arr1;
foreach($arr2 as $v) {
$result_array[] = $v;
}
This is, of course, working fine but I don't like this approach - imagine the situation when there will not be just 3 elements in second array...
Question: is there a better approach or at the best some built-in function (I do not know about)???
array_merge will work without any problem as your using numeric keys ... see the explanation below from the docs
If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.
emphasis mine
Array merge works fine for your numerically indexed arrays:
<?php
$arrayOne = array(
0 => 12345
,1 => "asdvsdfsasdfsdf"
,2 => "sdgvsdfgsdfbsdf"
);
$arrayTwo = array(
0 => 25485
,1 => "tyjfhgdfsasdfsdf"
,2 => "mojsbnvgsdfbsdf"
);
$arrayMerged = array_merge($arrayOne, $arrayTwo);
print_r($arrayMerged);
?>
output:
Array
(
[0] => 12345
[1] => asdvsdfsasdfsdf
[2] => sdgvsdfgsdfbsdf
[3] => 25485
[4] => tyjfhgdfsasdfsdf
[5] => mojsbnvgsdfbsdf
)

Categories