php array_chunk со сбалансированным количеством элементов

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

Итак, например, начиная с такого массива:

$input = array(1,2,3,4,5,6,7,8,9,10,11);

Я пытаюсь разработать функцию, которая принимает входной массив и количество элементов, ожидаемых для каждого фрагмента. Так, например, [ balanced_chunk($input, 3) ]

должен получить меня

0 => array(1,2,3)
1 => array(4,5,6)
2 => array(6,7,8)         #-- Value 6 is repeated
3 => array(9,10,11)

пока [ balanced_chunk($input, 5) ]

должен получить меня

0 => array(1,2,3,4,5)
1 => array(4,5,6,7,8)     #-- Value 4,5 are repeated
2 => array(7,8,9,10,11)   #-- Value 7,8 are repeated

и так далее

Для начала я разработал такую ​​функцию

function balanced_chunk($input, $size) {
    $step = ceil(count($input) / $size);
    $chunks = range(0, count($input), count($input) / $step);
    reset($chunks);
    while (list(,$start) = each($chunks)) {
            $start = (fmod($start, 1) <= 0.5 ? floor($start) : ceil($start));
            $clist[] = array_slice($input, $start, $size, true);
    }
    return($clist);
}

но по той причине, что в данный момент я пропускаю, у меня получается такой вывод:

[0] => Array (1,2,3,4,5)
[1] => Array (5,6,7,8,9)     #-- this element should instead start from 4...
[2] => Array (8,9,10,11)     #-- last element contains only 4 value

Просто чтобы сделать лучший пример, рассмотрим входной массив [ a,b,c,d,e,f,g,h,i,l,m,n,o,p ]

сбалансированный кусок с 5 элементами каждый должен быть

[ a,b,c,d,e ]
          [ f,g,h,i,l ]
                  [ l,m,n,o,p ] #-- letter 'l' is repeated twice on 3rd result

или (как допустимая альтернатива)

[ a,b,c,d,e ] 
        [ e,f,g,h,i ]           #-- letter 'e' is repeated twice on 2nd result
                    [ l,m,n,o,p ]

сбалансированный кусок с 8 элементами каждый должен быть

[ a,b,c,d,e,f,g,h ] 
            [ g,h,i,l,m,n,o,p ]  #-- letter 'g','h' are repeated twice

Я застрял! После нескольких попыток самостоятельно я не могу найти, как решить эту проблему.


person Stefano Radaelli    schedule 17.04.2014    source источник
comment
Как вы решаете, что действительно для 2-го массива, составленного из последовательности 1-11? Будет ли 6,7,8,9,10 также действительным, если 8,9 и 10 повторяются? Как насчет 5,6,7,8,9, где 5, 8 и 9 повторяются в другом месте (5 в первом массиве и 8 и 9 во втором)?   -  person madebydavid    schedule 17.04.2014
comment
не совсем так, как для моего масштаба, последовательность не будет сбалансирована. в вашем примере у меня было бы [1,2,3,4,5][6,7,8,9,10][7,8,9,10,11], что означает, что 0 значений 1-го результата являются общими со 2-м, а 4 результата 2-го результата являются общими с последним. В то время как сбалансированное распределение должно производить [1,2,3,4,5][4,5,6,7,8][7,8,9,10,11], где 2 значения 1-го результата совпадают со 2-м, а 2 результата 2-го - общими с 3-м.   -  person Stefano Radaelli    schedule 18.04.2014
comment
Очень интересный вызов. Откуда это? зачем вам это?   -  person mzedeler    schedule 18.04.2014
comment
Я собираюсь оптимизировать родительскую матрицу [ N, M ] с меньшей дочерней матрицей [ n, m ]. Задача состоит в том, чтобы вычислить меньшее количество повторений матрицы меньшего размера, необходимое для покрытия всей отцовской матрицы. Для начала я предполагал уменьшить входную матрицу как простой горизонтальный массив (например) из 75 элементов, который будет покрыт дочерним массивом всего из 10 элементов, но что [a] может перекрываться, и в случае перекрытия наложение должно быть сбалансированным посередине родительского массива.   -  person Stefano Radaelli    schedule 18.04.2014


Ответы (2)


Вы, вероятно, перешли к другим вещам сейчас! Но вот мой способ сделать это.

function balanced_chunk($input, $size)
{
    $len = count($input);
    $chunkSize = ceil($len / $size);
    $o = [];
    $i = 1;
    $k = 0;
    foreach ($input as $elem)
    {
        $o[$k][$i] = $elem;
        $k = ($i % $chunkSize == 0) ? $k+1 : $k;
        $i++;
    }
    return $o;
}
person kohloth    schedule 07.05.2015

На данный момент, ожидая найти «более умный» подход, я нашел это решение:

function balanced_chunk($input, $size) {
    $chunks   = ceil(count($input) / $size);
    $step     = count($input) / $chunks;
    $chunklist = array();
    for ($i = 0; $i < count($input); $i += $step) {
        $chunk = array_slice($input, floor($i), $size);
        if (count($chunk) < $size)  $chunk = array_slice($input, $size * -1, $size, true);
        $chunklist[] = $chunk;
    }
    return($chunklist);
}

Это означает, что, например... Пример №1: 11 элементов разбиты на куски по 3 в каждом:

$split = balanced_chunk(range(1, 11), 3));
/*
[ 1,2,3 ]
    [ 3,4,5 ][ 6,7,8 ][ 9,10,11 ]

In such case the fx needs to be better tuned as a better balanced output
has instead to be

[ 1,2,3 ][ 4,5,6 ]
             [ 6,7,8 ][ 9,10,11 ]
*/

Пример № 2: 11 элементов, разделенных на куски по 4 в каждом:

$split = balanced_chunk(range(1, 11), 4));
/*
[ 1,2,3,4 ]
      [ 4,5,6,7 ][ 8,9,10,11 ]

In such case the given output is exactly comparable with the alternative

[ 1,2,3,4 ][ 5,6,7,8 ]
                 [ 8,9,10,11 ]
*/

Пример №3: 11 элементов разбиты на куски по 5 в каждом:

$split = balanced_chunk(range(1, 11), 5));
/*
[ 1,2,3,4,5 ]
      [ 4,5,6,7,8 ]
            [ 7,8,9,10,11 ]
*/

Пример №4: 11 элементов разбиты на куски по 7 в каждом:

$split = balanced_chunk(range(1, 11), 7));
/*
[ 1,2,3,4,5,6,7 ]
        [ 5,6,7,8,9,10,11 ]
*/

Я приветствую советы или предложения по улучшению этого.

person Stefano Radaelli    schedule 22.04.2014