【问题标题】:PHP marge arrays with same keyPHP合并具有相同键的数组
【发布时间】:2021-06-23 21:53:08
【问题描述】:

我需要在 woocommerce 中对我的产品属性的数据结构进行排序,对每个属性及其值进行分组。

我现在的数组

array (size=5)
  0 => 
    array (size=1)
      'pa_color' => 
        array (size=1)
          0 => string 'red' (length=3)
  1 => 
    array (size=1)
      'pa_color' => 
        array (size=1)
          0 => string 'red' (length=3)
  2 => 
    array (size=2)
      'pa_color' => 
        array (size=1)
          0 => string 'gray' (length=4)
      'pa_modello' => 
        array (size=1)
          0 => string 'modello2' (length=8)
  3 => 
    array (size=1)
      'pa_color' => 
        array (size=1)
          0 => string 'yellow' (length=6)
  4 => 
    array (size=0)
      empty

我需要合并类似的东西:

array (size=1)
      'pa_color' => 
        array (size=1)
          0 => string 'red' (length=3)
          1 => string 'gray' (length=4)
          2 => string 'yellow' (length=6)
       
       'pa_modello' => 
            array (size=1)
              0 => string 'modello2' (length=8)

将相同键的值分组到一个数组中。

提前致谢

【问题讨论】:

  • 任何答案是否提供了帮助?

标签: php wordpress multidimensional-array woocommerce array-merge


【解决方案1】:
global $wp_query;
    $obj = get_queried_object();
    foreach ($wp_query->posts as $_post) {

        $_product = wc_get_product($_post->ID);
        $wc_attr_objs = $_product->get_attributes();
        $prod_attrs = [];

        foreach ($wc_attr_objs as $wc_attr => $wc_term_objs) {
            $prod_attrs[$wc_attr] = [];

            $wc_terms = $wc_term_objs->get_terms();


            foreach ($wc_terms as $wc_term) {
                 array_push($prod_attrs[$wc_attr], $wc_term->slug);


                var_dump($prod_attrs);


             }
        }

      $totals[] = $prod_attrs;

    } 

【讨论】:

  • 纯代码答案在 Stack Overflow 上的价值很低,因为它们错过了教育未来研究人员的绝佳机会。
  • 显示您的数据是如何实际生成的,在这个问题中很高兴知道。这样可以根据您的应用程序定制答案,而不是通用技术。
【解决方案2】:

$array 是你的数组:

foreach ($array as $item)
{
   if ($item['pa_color']['0']) $color[ $item['pa_color']['0'] ] = $item['pa_color']['0'];
   if ($item['pa_modello']['0']) $modello[$item['pa_modello']['0']] = $item['pa_modello']['0'];
// this loop will remove the duplicated values and I Assume each pa_color , pa_modello in the original array contains only one element with 0 as a key
}
foreach ($color as $c) $newArray['pa_color'][] = $c;
foreach ($modello as $m) $newArray['pa_modello'][] = $m;

这应该可以完成工作。

编辑:

动态属性注释:

foreach ($array as $item)
   foreach (array_keys($item) as $key) // getting the keys ex: pa_color 
   {
      if ($item[$key]['0']) {
         $temparray[$key][ $item[$key]['0'] ] = $item[$key]['0'];
      }
      // this loop will remove the duplicated values and I Assume each key in the original array contains only one element with 0 as a key
// the temparray will contain in its keys ($key) the pa_color , pa_module.. etc 
// each of them will be an array with the key=value approach .. in case having two "red" it will not duplicate 
   }
// finally making it zero based array 
foreach ($temparray as $key=>$item) // ex: $temparray['pa_color']['red'] = 'red'
   foreach ($item as $value) // ex: $item['red'] = 'red'
      $newArray[$key][] = $value; // ex: $newArray['pa_color'][0] = 'red';

看起来很复杂..我找不到更好的方法。

【讨论】:

  • 我有一个动态属性怎么可以循环一些变量?我在答案中发布了完整的代码
  • @Gozer 我已经编辑了答案,检查它是否适合你。
  • 请修正您的 sn-ps 中的格式。这并不容易阅读。你的 sn-ps 也缺少他们的教育解释。
  • @mickmackusa 感谢您的建议。我会解决的
  • @mickmackusa 我希望编辑是正确的.. 我试图提供帮助,但我想我搞砸了。这对我来说太复杂了。
【解决方案3】:

循环遍历第一级条目,然后添加一个嵌套循环以从子数组中的所需键和值创建变量。

由于您的最深子数组中只有一个元素,您可以use "array destructuring" inside of the nested loop 将唯一元素值分配为$value

通过将$value 声明为结果数组中深度值的键,确保输出中的唯一值。

如果您确实希望重新索引子数组,您可以使用 array_map()array_values() 进行此操作 - 但仅在必要时才这样做。

代码:(Demo)

$result = [];
foreach ($array as $entries) {
    foreach ($entries as $key => [$value]) {
        $result[$key][$value] = $value;
    }
}

var_export($result);

输出:

array (
  'pa_color' => 
  array (
    'red' => 'red',
    'gray' => 'gray',
    'yellow' => 'yellow',
  ),
  'pa_modello' => 
  array (
    'modello2' => 'modello2',
  ),
)

附言如果您的深层子数组可能有多个元素,那么只需使用另一个循环来适应它以迭代该级别。

$result = [];
foreach ($array as $entries) {
    foreach ($entries as $key => $values) {
        foreach ($values as $value) {
            $result[$key][$value] = $value;
        }
    }
}

翻译成您在自我回复帖子中编写的代码,我认为它可能如下所示:

global $wp_query;
$prod_attrs = [];
foreach ($wp_query->posts as $_post) {
    foreach (wc_get_product($_post->ID)->get_attributes() as $wc_attr => $wc_term_objs) {
        foreach ($wc_term_objs->get_terms() as $wc_term) {
             $prod_attrs[$wc_attr][$wc_term->slug] = $wc_term->slug;
         }
    }
}
var_export($prod_attr);

【讨论】:

  • 使用 key 的值来避免重复是非常聪明的。
【解决方案4】:

最简单的组合数组的方法是在数组数组上使用 array_merge_recursive 和 splat 运算符 (...)。

splat 运算符将解包可用于递归合并它们的数组。

$expected = array_merge_recursive(...$array);

此外,如果您只需要合并数组中的唯一值,您可以像这样使用array_map

$unique = array_map('array_unique', $expected);

more about splat operator

在 cmets 之后编辑

因为我自己一直在大量使用这种方法,所以我做了一些测试,看看哪个更快。

分享结果:

问题:这两种方法哪个更快?

方法一:array_map('array_unique', array_merge_recursive(...$array));
方法2:使用foreach,如mickmackusa's answer中所述

使用大小为 5、50、100 和 500 的数组进行测试
将每个函数循环 10000 和 100000。

T1 是array_merge_recursive 花费的时间,T2 是foreach 花费的时间

array_size loop_count T1 T2 faster diff
5 10,000 0.041 0.0206 foreach 0.0204
5 100,000 0.2061 0.2082 array_merge_recursive 0.002
5 500,000 1.0315 1.0611 array_merge_recursive 0.0296
50 10,000 0.046 0.1878 array_merge_recursive 0.1418
50 100,000 0.4452 1.8877 array_merge_recursive 1.4425
100 10,000 0.0697 0.3729 array_merge_recursive 0.3032
100 100,000 0.6795 3.7464 array_merge_recursive 3.0669
500 10,000 0.2542 1.8674 array_merge_recursive 1.6132
500 100,000 2.5359 18.6922 array_merge_recursive 16.1562

结论:

  1. 对于小型阵列,使用什么并不重要。仅在 500,000 次循环后我才注意到差异
  2. 不同之处在于您使用更大的数组。当使用计数为 500 的数组时,foreach 需要 16.1562 秒以上

因此,如果您有较小的数组,请使用您想要的任何东西。对于更大的数组,绝对避免使用foreach 并使用array_merge_recursive

链接到test sandbox

【讨论】:

  • 我还考虑了 array_merge_recursive() 与 splat 运算符 (stackoverflow.com/a/53028357/2943403),但它不会过滤掉重复项,因此它需要另一组循环来提供所需的内容。 3v4l.org/nVCEU 这就是为什么我没有建议这种简洁的技术。 OP 没有在问题中显示数据填充脚本 - 在创建 $array 之前创建所需的结构会更好。这不是你的错,这不是一个理想的发布问题。
  • @mickmackusa 是的,它不会删除重复项,这就是我提供array_unique 选项的原因。
  • 是的,我明白了。我是说通过不同的解决方案(如我的答案中的那个)可以避免必须重新迭代结果。 OP 必须调用 WP 函数来收集这些数据,因此在初始迭代期间存储唯一数据比创建 $array(不需要的数据结构)然后调用递归函数,然后循环最后一次更有意义删除重复项。
  • @mickmackusa 关于另一个问题,您说 funky 替代方案(我无法想象实际使用它,除非我正在为我不关心的人编写代码) 为什么这么说,使用这种方法有什么负面影响吗?我喜欢只用一两行代码就能做到这一点。使其可读
  • 我发现在具有有限深度的数据结构上使用递归函数调用是不合适的。 (只是我个人的喜好)它是 funky 因为我认为它的可读性/直观性和抽象性更差。
猜你喜欢
  • 2014-03-12
  • 2021-12-09
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 2015-01-04
  • 2016-06-09
  • 1970-01-01
相关资源
最近更新 更多