【问题标题】:How to group elements of array?如何对数组的元素进行分组?
【发布时间】:2011-06-16 14:21:54
【问题描述】:

我有一组文件夹/路径:

$arr = Array
(
    0 => Array
         (
              'name' => 'aaa'
         ),

    1 => Array
         (
              'name' => 'aaa\bbb'
        ),

    2 => Array
         (
              'name' => 'aaa\bbb\ccc'
         ),
    3 => Array
         (
              'name' => 'ddd'
         )
);

我想将其转换为多维(树状)数组(保持结构:索引/键和值/名称):

 aaa 
    bbb
       ccc
 ddd

有什么建议吗?

【问题讨论】:

  • 如果第一个数组是0=>'aaa' 1=>'aaa\bbb' 2=>'aaa\ddd\ccc',您希望输出看起来如何?或者这永远不会成为问题,因为它们总是相同的?
  • 对不起。我已经更正了我的示例。
  • 我发现您决定将最深层次的元素作为价值并将所有父母作为关键元素有点奇怪。您如何知道从数组中获取什么 - 键或值?
  • 您的原始数组甚至没有ddd 元素,但转换后的数组有一个。
  • @mkilmanas:有什么建议吗?

标签: php arrays tree


【解决方案1】:

试试:

$arr = array(
   array('name' => 'aaa'),
   array('name' => 'aaa\bbb'),
   array('name' => 'aaa\bbb\ccc'),
   array('name' => 'ddd'),
   array('name' => 'ddd\zzz'),
   array('name' => 'zzz'),
   array('name' => 'ddd\zzz\fff'),
);

$new = array();
$helper = array();
foreach ($arr as $i => $entry) {
    $parent =& $new;
    /**
     * One could use:
     *   explode(DIRECTORY_SEPARATOR, $entry['name'])
     * 
     * instead of '\\' if you're dealing with file-structures
     */
    foreach ($path = explode('\\', $entry['name']) as $ii => $element) {
        $subPath = implode('.', array_slice($path, 0, $ii + 1));

        if (isset($helper[$subPath])) {
            $parent =& $helper[$subPath];
            continue;
        }

        $parent[$i] = array('name' => $element);
        $helper[$subPath] =& $parent[$i];
    }
}

print_r($new);

输出

Array
(
    [0] => Array
        (
            [name] => aaa
            [1] => Array
                (
                    [name] => bbb
                    [2] => Array
                        (
                            [name] => ccc
                        )

                )

        )

    [3] => Array
        (
            [name] => ddd
            [4] => Array
                (
                    [name] => zzz
                    [6] => Array
                        (
                            [name] => fff
                        )

                )

        )

    [5] => Array
        (
            [name] => zzz
        )

)

【讨论】:

  • 我喜欢这个解决方案,做得很好。我唯一的建议可能是使用 DIRECTORY_SEPARATOR 而不是常量 '\\'
  • @Brad Christie 谢谢 :) 关于DIRECTORY_SEPARATOR;我真的不知道如何解释字符串的(含义),所以我只是照原样接受。但我想你是对的,所以我会更新代码。 :)
  • 酷,但如何保持结构?
  • @Yoshi:我要假设(你知道我们这样做时会发生什么)路径是由 PHP 方法生成的,所以它们将保留在本机格式。但是您可能是绝对正确的,它们与操作系统本身无关,在这种情况下,PHP 常量可能会破坏它。
  • @Ken 你是什么意思? (name 索引 ??)
【解决方案2】:
$newarr=array();

foreach ($arr as $element) {
    $currentroot=$newarr;
    $pieces=explode('\\', $element);
    for ($x=0; $x<=count($pieces); x++) {
        $currentroot[$pieces[$x]]=array();
        $currentroot=$currentroot[$pieces[$x]];
    }
}

未经测试,但应该可以帮助您入门。您需要添加一个条件来检查它是否是最后一块,并使其成为字符串值而不是数组。

【讨论】:

    【解决方案3】:

    好吧,必须在两个函数中完成,但这里是:

    // Directory Array to Hierarchy
    function _DAtoH($path, $result = null)
    {    
      if (empty($path))      return array();
      if (is_null($result))  $result = array();
    
      $path = explode(DIRECTORY_SEPARATOR, $path);
      $curr = array_shift($path);
      if (!isset($result[$curr]))
        $result[$curr] = array();
      $result[$curr] = _DAtoH(implode(DIRECTORY_SEPARATOR, $path), $result[$curr]);
      return $result;
    }
    function DAtoH($arr)
    {
      $result = array();
      foreach ($arr as $a)
        $result = _DAtoH($a,$result);
      return $result;
    }
    

    传递底部函数(_DAtoH 只是一个递归助手)您在原始问题 (var_dump(DAtoH($arr));) 中指定的数组,您应该会收到:

    array(2) {
      ["aaa"]=>
      array(2) {
        ["bbb"]=>
        array(1) {
          ["ccc"]=>
          array(0) {
          }
        }
        ["fff"]=>
        array(0) {
        }
      }
      ["ddd"]=>
      array(1) {
        ["eee"]=>
        array(0) {
        }
      }
    

    }

    (注意:我添加了一些文件夹路径只是为了测试它,因此 fff、eee 等)

    【讨论】:

      【解决方案4】:

      对于新要求:

      $arr = array(
         array('name' => 'aaa'),
         array('name' => 'aaa\bbb'),
         array('name' => 'aaa\bbb\ccc'),
         array('name' => 'ddd'),
      );
      
      function traverse(array $array) {
          $mark=array_shift($array);
          return array($mark => $array ? traverse($array) : array() );
      }
      
      $out = array();
      foreach($arr as $path)
      {
          ($add=traverse(explode('\\',$path['name'])))
              && $out[key($add)]=current($add)
              ;
      }
      

      输出:

      array(2) {
        ["aaa"]=>
        array(1) {
          ["bbb"]=>
          array(1) {
            ["ccc"]=>
            array(0) {
            }
          }
        }
        ["ddd"]=>
        array(0) {
        }
      }
      

      老问题:

      旧问题有以下要求:

      $arr = array(
         0 => 'aaa',
         1 => 'aaa\bbb',
         2 => 'aaa\bbb\ccc',
      );
      
      function traverse(array $array) {
          $mark=array_shift($array);
          return $array ? array($mark => traverse($array)) : $mark;
      }
      
      $out = array();
      foreach($arr as $path)
      {
          is_array($add=traverse(explode('\\',$path)))
              && $out[key($add)]=current($add)
              ;
      }
      

      经过测试,给出以下输出:

      array(1) {
        ["aaa"]=>
        array(1) {
          ["bbb"]=>
          string(3) "ccc"
        }
      }
      

      【讨论】:

      • 是否可以将 aaa\bbb 重命名为 bbbaaa\bbb\ccc 重命名为 ccc ?
      • @Ken 在输入数组中是可能的,是的。但是对于输出数组,键已经是那种形式了。
      猜你喜欢
      • 2020-08-07
      • 1970-01-01
      • 2019-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-13
      相关资源
      最近更新 更多