2010-12-09 2 views
2

Оригинальное название было алгоритм в список каталогов/файлов только от конкретного объекта пути (S3, Google Storage)Эквивалент Glob(), который будет работать с массивом вместо файловой системы

https://gist.github.com/9a353e1589ff3ce84c02

Может ли кто-нибудь предложить алгоритм для перечисления каталогов/файлов только в пределах определенного пути объекта? Например, ahostel.lt/img/ должен содержать только перечни languages and psd, and files background.png, [..]. Мой алгоритм длинный и использует три цикла foreach, что плохо для производительности, но, возможно, у кого-то есть лучшее представление о том, как его достичь, используя регулярное выражение или другие альтернативы.

Моя система работает на PHP, но общий логарифм будет очень хорош, если можно преобразовать его в PHP.

Другими словами, я ищу алгоритм, подобный glob(), который будет работать с Array вместо файловой системы.

упрощенный список каталогов: https://gist.github.com/d0c3fa12d4b894938ba5

+0

https://gist.github.com/14405d3fa83eb50c172b – Gajus 2010-12-09 10:17:44

ответ

0
$already_included  = array(); 

    foreach($list as $key => $object) 
    { 
     $clean_key = substr($key, strlen($uri)); 
     $explode = explode('/', $clean_key); 

     if(count($explode) >= 1 && !in_array($explode[0], $already_included)) 
     { 
      $already_included[] = $explode[0]; 

      $files['directories'][] = array 
      (
       'path'   => $uri . $explode[0] . '/', 
       'name'   => $explode[0], 
       'last_modified' => $object['last_modified'], 
      ); 

     } 

     if(substr_count($key, '/', $path_str_length) === 0) 
     { 
      $basename = pathinfo($key, PATHINFO_BASENAME); 

      if(strpos($basename, '.') !== FALSE) 
      { 
       $files['files'][] = array 
       (
        'path'   => $key, 
        'name'   => $basename, 
        'size'   => $object['size'], 
        'last_modified' => $object['last_modified'], 
       ); 
      } 
      elseif(strrpos($basename, '_$folder$') !== FALSE) 
      { 
       $files['directories'][] = array 
       (
        'path'   => $key, 
        'name'   => substr($basename, 0, -9), 
        'last_modified' => $object['last_modified'], 
       ); 
      } 

     } 
    } 
1

Другими словами, я ищу алгоритм, как Glob(), который будет работать с массивом вместо файловой системы.

Вы можете использовать ArrayIterator и завернуть его в обычай FilterIterator

class CustomFilterIterator extends FilterIterator 
{ 
    public function accept() 
    { 
     return strpos($this->key(), 'ahostel.lt/img/') === 0 && 
      pathinfo($this->key(), PATHINFO_EXTENSION) === 'png'; 
    } 
} 

Метод принимает должен возвращать логическое значение. Если логическое значение TRUE, текущий итерационный элемент будет рассмотрен для включения в итерацию. В приведенном выше примере все, что не начинается с 'ahostel.lt/img/' и заканчивается расширением png, будет проигнорировано. Вы можете добавить дополнительные критерии фильтрации по своему усмотрению. Чтобы получить доступ к ключу, вы используете $this->key(). Для значения используйте $this->current().

Использование (codepad)

$iterator = new CustomFilterIterator(new ArrayIterator($yourArray)); 

// to create a subset of the original array use 
$filteredArray = iterator_to_array($iterator); 

// or use good old foreach 
foreach ($iterator as $path => $fileProperties) { 
    var_dump($path, $fileProperties); 
} 

В качестве альтернативы или дополнения, вы можете использовать RegexIterator.

Два основных преимущества при использовании итераторы является повторным использованием и тестопригодность: итераторы могут быть уложены, поэтому указанные выше CustomFilterIterator может быть разбит на два итераторы, как PathFilter и ExtensionFilter. Затем вы просто оберните ArrayIterator в оба итератора фильтра, чтобы создать гибкую цепочку фильтра сверху. Поскольку итераторы являются классами, их можно легко протестировать и высмеять в классах, у которых итератор является зависимостью, чего вы не можете сделать, поставив логику фильтрации в цикл foreach.

Дополнительные ресурсы о итераторы и SPL в целом:

4

Похоже, у вас есть простой массив, так что здесь является альтернативой, которая фильтрует массив, используя регулярное выражение на клавишах.

// Matches only immediate files of ahostel.lt/img/ 
$pattern = '#^ahostel\.lt/img/[^/]+\.[^/]+$#D'; 
$keys = preg_grep($pattern, array_keys($array)); 
$items = array_intersect_key($array, array_flip($keys)); 

Другим способом, так как итераторы являются удивительными, без написания на заказ один, будет использовать RegexIterator сделать работу фильтрации ключей. Затем вы просто перебираете фильтрованный итератор или используете iterator_to_array(), чтобы получить массив, содержащий только отфильтрованные значения.

$items = new RegexIterator(
    new ArrayIterator($array), 
    '#^ahostel\.lt/img/[^/]+\.[^/]+$#D', 
    RegexIterator::MATCH, 
    RegexIterator::USE_KEY 
); 

Есть еще bazillion различные способы, которые можно использовать или создавать фильтрацию итератора, даже используя что-то вроде fnmatch() в accept() методом FilterIterator использовать подстановочные знаки как с glob().

class GlobKeyFilterIterator extends FilterIterator 
{ 
    protected $pattern; 
    public function __construct(Iterator $it, $pattern) 
    { 
     $this->pattern = $pattern; 
     parent::__construct($it); 
    } 
    public function accept() 
    { 
     return fnmatch($this->pattern, $this->key(), FNM_PATHNAME); 
    } 
} 

$items = new GlobKeyFilterIterator(
    new ArrayIterator($array), 
    'ahostel.lt/img/*.*' 
); 
+0

@ Гордон, вы проповедуете там хор. – salathe 2010-12-09 22:25:50

+1

@ Гордон, я знаю, что вы не проповедовали, это всего лишь очередь фразы. :) Я добавил пример использования `fnmatch()` с `FilterIterator`, который ближе всего к« эквиваленту glob() »в вопросе. – salathe 2010-12-09 22:46:01

1

Многие программисты PHP имеют тенденцию к чрезмерному усложнению вещей. Простое решение всегда имеет простое решение.

$result = array(); 
foreach($dir as $k => $v) 
    if(strpos($k, 'ahostel.lt/img/') === 0) 
     $result[$k] = $v; 

Не только это более читаемо, чем любой свернутый код smart-alec, но и намного быстрее.

Смежные вопросы