如何对数组中的元素进行分组?

3

我有一个文件夹/路径的数组:

$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',你希望输出的样子是什么?或者这从来不是问题,因为它们总是相同的? - NorthGuard
对不起。我已经更正了我的示例。 - Ken
我认为将最深层元素作为值,所有父级都作为键的决定有些奇怪。你将如何知道从数组中取什么 - 键还是值? - mkilmanas
你的原始数组甚至没有 ddd 元素,但转换后却有一个。 - anubhava
@mkilmanas:有什么建议吗? - Ken
4个回答

5

尝试:

$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
@Brad Christie 谢谢 :) 关于 DIRECTORY_SEPARATOR;我其实不太清楚如何解释这个字符串的含义,所以我只是按照原样使用了它们。但我想你是对的,所以我会更新代码。 :) - Yoshi
很酷,但如何保持结构? - Ken
@Yoshi:我要“假设”(你知道我们这样做会发生什么)路径是由PHP方法生成的,因此它们将保持原生格式。但你可能是完全正确的,它们对操作系统本身可能没有任何影响,在这种情况下,PHP常量可能会破坏它。 - Brad Christie
@Ken 你的意思是什么?(name 索引是什么意思?) - Yoshi
显示剩余2条评论

0
$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]];
    }
}

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


0

针对新的需求:

$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
@Ken 输入数组中是可能的,但对于输出数组来说,键已经以那种形式存在。 - hakre

0

好的,必须用两个函数来完成,但是这里开始:

// 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等。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接