请考虑以下这个集合:
$collection = Array (
$arr1 = Array ( 1 => 10.0, 2 => 20.0, 3 => 50.0, 4 => 80.0, 5 => 100.0 ),
$arr2 = Array ( 3 => 20.0, 5 => 20.0, 6 => 100.0, 7 => 10.0 ),
$arr3 = Array ( 1 => 30.0, 3 => 30.0, 5 => 10.0, 8 => 10.0 )
);
考虑这个基于$ collection中包含的数组的交集的理论输出,考虑它们的数组键与基于单个值的平均值的相应值:
$output = Array ( 3 => 33.3333, 5 => 43.3333 );
可以用优雅的方式使用像array_intersect_ *这样的本机PHP函数来解决这个问题吗?
如果没有,你能否建议我一个优雅的解决方案,并不一定需要一个外在丑陋的foreach?
请记住,需要相交的数组数量不固定。它可以是2个输入数组,因为它可以是1000个输入数组。 键将始终为整数,值将始终为浮点数或整数。
换句话说:
$collection = [
$arr1 = [ ... ];
$arr2 = [ ... ];
$arr3 = [ ... ];
...
$arrn = [ ... ];
];
$output = [ intersected and weighted array based (on comparison) on keys from $arr1 to $arrn, and (on values) from the value averages ];
答案 0 :(得分:2)
计算一次输入数组。
$n = count($collection);
按键计算所有子阵列的交集。
$intersection = array_intersect_key(...$collection);
// PHP5: $intersection = call_user_func_array('array_intersect_key', $input);
通过对交叉点中每个键的输入数组中的列进行平均来构建结果。
$output = [];
foreach ($intersection as $key => $value) {
$output[$key] = array_sum(array_column($collection, $key)) / $n;
}
如果您真的想要完全避免使用foreach
,则可以使用array_map
。
$output = array_map(function($key) use ($collection, $n) {
return array_sum(array_column($collection, $key)) / $n;
}, array_keys($intersection));
但在我看来,这只会增加不必要的复杂性。
注意:$intersection
中的值将是第一个子数组中的单个值,但它们并不重要;在生成输出时,它们被忽略了。如果你在foreach中有一个无用的$value
变量,那么你可以改为foreach (array_keys($intersection) as $key)
,但我选择避免不必要的函数调用。
答案 1 :(得分:1)
您可以将数组合并为一个,并使用array_sum和count()来获得平均值。
$arr1 = Array ( 'one' => 10, 'two' => 20, 'three' => 50, 'four' => 80, 'five' => 100 );
$arr2 = Array ( 'three' => 20, 'five' => 20, 'six' => 100, 'seven' => 10 );
$arr3 = Array ( 'one' => 30, 'three' => 30, 'five' => 10, 'eight' => 10 );
$array = array_merge_recursive($arr1,$arr2,$arr3);
$key= "two";
If(is_array($array[$key])){
$avg = array_sum($array[$key])/count($array[$key]);
}Else{
$avg = $array[$key];
}
Echo $avg;
<小时/> 编辑以关注$ collection数组。
然后尝试一下。使用数组列获取正确的键并使用array_sum并计数以获得平均值。
$collection = array(
Array ( 'one' => 10, 'two' => 20, 'three' => 50, 'four' => 80, 'five' => 100 ),
Array ( 'three' => 20, 'five' => 20, 'six' => 100, 'seven' => 10 ),
Array ( 'one' => 30, 'three' => 30, 'five' => 10, 'eight' => 10 ));
$key= "three";
$array = array_column($collection, $key);
If(count($array) != 1){
$avg = array_sum($array)/count($array);
}Else{
$avg = $array[0];
}
Echo $avg;
最终编辑。
这里我遍历第一个子阵列并使用数组列找到所有匹配的键 如果密钥数与收集计数相同,则密钥存在于所有子阵列中,应该“保存”。
$collection = array(
Array ( 'one' => 10, 'two' => 20, 'three' => 50, 'four' => 80, 'five' => 100 ),
Array ( 'three' => 20, 'five' => 20, 'six' => 100, 'seven' => 10 ),
Array ( 'one' => 30, 'three' => 30, 'five' => 10, 'eight' => 10 ));
Foreach($collection[0] as $key => $val){
$array = array_column($collection, $key);
If(count($array) == count($collection)){
$avg[$key] = array_sum($array)/count($array);
}
}
Var_dump($avg);
答案 2 :(得分:1)
我想可以这样做:
<?php
$intersecting_arrays = Array (
0 => Array ( 'one' => 10, 'two' => 20, 'three' => 50, 'four' => 80, 'five' => 100 ),
1 => Array ( 'three' => 20, 'five' => 20, 'six' => 100, 'seven' => 10 ),
2 => Array ( 'one' => 30, 'three' => 30, 'five' => 10, 'eight' => 10 )
);
$temp = $intersecting_arrays[0];
for($i = 1; $i < count($intersecting_arrays); $i++) {
$temp = array_intersect_key($temp, $intersecting_arrays[$i]);
}
$result = Array();
foreach(array_keys($temp) as $key => $val) {
$value = 0;
foreach($intersecting_arrays as $val1) {
$value+= $val1[$val];
}
$result[$key] = $value / count($intersecting_arrays);
}
print_r($temp);
print_r($result);
以这种方式,它并不取决于您拥有多少阵列。 在这里,您可以获得所有阵列中的交叉点,然后使用收集的键计算平均值。
答案 3 :(得分:1)
好的,对于未知数量的输入数组,我肯定会先使用两个嵌套的foreach循环来将它们组合起来 - 将未知数字放入array_merge_recursive或类似的将是困难的。
$input = [
0 => [ 'one' => 10, 'two' => 20, 'three' => 50, 'four' => 80, 'five' => 100],
1 => [ 'three' => 20, 'five' => 20, 'six' => 100, 'seven' => 10],
2 => [ 'one' => 30, 'three' => 30, 'five' => 10, 'eight' => 10]
];
$combined = [];
foreach($input as $array) {
foreach($array as $key => $value) {
$combined[$key][] = $value;
}
}
$averages = array_map(function($item) {
return array_sum($item)/count($item);
}, $combined);
var_dump($averages);
请注意,此解决方案不需要在array_map回调中检查数组与单个整数,因为与array_merge_recursive不同,循环内的$combined[$key][]
会看到即使只有一个值的键也会具有该值在数组中。
编辑:
但请记住,并非所有的密钥都会被考虑在内
啊,好吧,所以你只想要那些多次出现的键的平均值。通过在使用array_map之前过滤组合数组,可以很容易地解决这个问题:
$combined = array_filter($combined, function($v, $k) {
return count($v) != 1;
}, ARRAY_FILTER_USE_BOTH );
集成到上述解决方案中:https://3v4l.org/dn5ro
编辑#2
[Andreas的评论]我认为“one”不应该在输出中,因为它不在所有三个数组中。
啊,我看到......即使从例子中也看不出这是实际需要的结果:-)然后我的过滤必须再次修改一下,并考虑输入数组的数量: / p>
$combined = array_filter($combined, function($v, $k) use($input) {
return count($v) == count($input);
}, ARRAY_FILTER_USE_BOTH );