Могу ли я объединить имена каталогов в массив, а затем использовать их по значению файла?

Может ли кто-нибудь посоветовать, могу ли я написать функцию для usort, которая будет делать следующее в PHP:

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

Вот что я хочу сделать:

подставить список каталогов в вызов массива $dirs

используйте функцию usort, чтобы сделать следующее:

  1. Прочитайте два файла (file1.txt и file2.txt) в каждом каталоге и перемножьте их вместе, чтобы создать третье число, называемое $value.
  2. Отсортируйте исходный массив $dirs в порядке убывания по значению $ для каждого каталога.

Хорошо - я могу подставить файлы следующим образом:

$dirs = glob('*',GLOB_NOSORT|GLOB_ONLYDIR); 

и я могу достаточно легко получить значения, используя file_get_contents, но я не могу понять, как объединить все это в функцию для usort.


person Chris Jones    schedule 13.05.2013    source источник
comment
Вы можете использовать intval для возвращаемого значения file_get_contents, если они являются целыми числами. Я думаю, что примеры на php.net/manual/en/function.usort.php с ними несложно работать. Наконец, я надеюсь, что это задание, а не реальная база данных.   -  person Adder    schedule 13.05.2013
comment
Спасибо за помощь. Adder. Итак, вызывает ли usort функцию несколько раз, и было бы расточительно, если бы нужно было фильтровать сотни каталогов? Не лучше ли мне пройтись по первому массиву, возвращенному usort, взять значения только один раз для каждого каталога и добавить их в другой (многомерный) массив с именем каталога и значением, а также использовать этот второй массив ›   -  person Chris Jones    schedule 13.05.2013
comment
Да, вычисление произведения сначала было бы быстрее.   -  person Adder    schedule 13.05.2013


Ответы (3)


Попробуй это:

<?php

$dirs = array();
foreach (glob('*',GLOB_NOSORT|GLOB_ONLYDIR) as $dir) {
    $value = 
        (int)file_get_contents($dir.'/file1.txt') * 
        (int)file_get_contents($dir.'/file2.txt') ;
    $dirs[] = array(
        'path'  => $dir,
        'value' => $value,
    );
}

usort($dirs, function($a, $b) {
    return $b['value'] - $a['value'];
});

Затем вы хотите получить одномерный результат,

$dirs = array_map(function ($dir) {
    return $dir['path'];
}, $dirs);
person mpyw    schedule 13.05.2013
comment
Просто написание $b['value'] - $a['value']; возвращает значение и в PHP, я просто знаком с этим из других языков? - person Adder; 13.05.2013

Следующий фрагмент сделает свое дело:

$dirs = glob('*',GLOB_NOSORT|GLOB_ONLYDIR); 
usort($dirs, function ($a, $b) {
    $val_a = $val_b = 1;
    foreach(scandir($a) as $file) {
        if(strpos($file, '.') === 0) {
            continue;
        }   
        $val_a *= intval(trim(file_get_contents($a. '/' . $file)));
    }   
    foreach(scandir($b) as $file) {
        if(strpos($file, '.') === 0) {
            continue;
        }   
        $val_b *= intval(trim(file_get_contents($b. '/' . $file)));
    }   

    if($val_a === $val_b) {
        return 0;
    } else if($val_a > $val_b) {
        return 1;
    } else {
        return -1; 
    }   
});

var_dump($dirs);
person hek2mgl    schedule 13.05.2013

Предполагая, что вы используете версию 5.3.0 или выше, для этого можно использовать анонимную функцию. Ниже вы увидите функцию buildSort, которая возвращает объект функции (называемый в PHP «замыканием», хотя в некоторых кругах ведутся бурные споры о правильности применения этого термина). Мы будем использовать ее для «запоминания» чтения dir/file1.txt и dir/file2.txt, а также математические операции, поэтому нам нужно выполнить их только один раз для каждого каталога:

<?php

function buildSort(&$values) {
        return function ($a, $b) use(&$values) {
                if (!isset($values[$a])) {
                        $values[$a] = file_get_contents($a.'/file1.txt')*
                          file_get_contents($a.'/file2.txt');
                }
                if (!isset($values[$b])) {
                        $values[$b] = file_get_contents($b.'/file1.txt')*
                          file_get_contents($b.'/file2.txt');
                }

                return strcmp($values[$a], $values[$b]);
        };
}


$dirs = glob('*',GLOB_NOSORT|GLOB_ONLYDIR);
$values = array();
$sort = buildSort($values);

usort($dirs, $sort);
var_dump($dirs);

Ответ, который позволяет избежать передачи $values ​​по ссылке, оставлен в качестве упражнения для читателя. :)

person TML    schedule 14.05.2013