簡體   English   中英

重組數組的最快方法?

[英]Quickest way to restructure an array?

我有一個數組,其中可以包含多個項目,例如:

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
etc

我需要最快的方法來重組這個數組,使其最多有 X 個項目。 所以如果我說 X 是 3,那么結果數組必須是:

Item 1 , Item 2
Item 3, Item 4
Item 5, Item 6
etc

或者如果它有 7 個項目,它將是:

Item 1 , Item 2, Item 3,
Item 4, Item 5, 
Item 6, Item 7

什么是最簡單的方法來做到這一點?

我從這個開始,但似乎真的必須有一個更簡單的方法:

foreach ($addressParts as $part)
{
    if (empty($part)) continue;
    if (empty($addressLines[$count]))  $addressLines[$count] = '';
    $addressLines[$count] .= $part;
    $count++;
    if ($count > 2) $count = 0;
}

此外,這行不通,因為你最終會得到這樣的結果:

item 1, item 4, item 7
item 2, item 5
item 3, item 6

......這是錯誤的。 有什么想法嗎?

更新

如果我開始:

Array
(
    [0] => item 1
    [1] => item 2
    [2] => item 3
    [3] => item 4
    [4] => item 5
    [5] => item 6
    [6] => item 7
)

我想以:

Array
(
    [0] => item 1, item 2, item 3
    [1] => item 4, item 5
    [2] => item 6, item 7
)

有道理嗎?

此函數根據您的示例將元素組合到一個新數組中。 它處理任意數量的輸入元素。

function ReduceArray($input, $length) {
        $frac = $length / count($input);
        $frac = $frac + 0.0001;    // Offset for float calculations
        $index = 0.0;

        // Copy the elements, rolling over on $index
        $temp = array();
        foreach ($input as $part) {
                $i= floor($index);
                if (!isset($temp[$i])) {
                        $temp[$i] = array($part);
                } else {
                        $temp[$i][] = $part;
                }
                $index += $frac;
        }

        // Combine the sub arrays
        $output = array();
        foreach ($temp as $line) {
            $output[] = implode(', ', $line);
        }
        return $output;
}

$input = array('Item 1',  'Item 2',  'Item 3',  'Item 4',  'Item 5',  'Item 6', 'Item 7');
$output = ReduceArray($input, 3);
print_r($output);

輸出

Array
(
    [0] => Item 1, Item 2, Item 3
    [1] => Item 4, Item 5
    [2] => Item 6, Item 7
)

根據給定的輸出編輯“固定”輸出。

編輯 請參閱九個元素的評論,最多測試 12 個元素。 感謝 sectus

對於每個組,計算第一個元素的偏移量和組長度,從輸入數組中復制該切片。

function array_group_elements($array, $groups) {
  $result = array();
  $count = count($array);
  // minimum in each group
  $limit = floor($count / $groups);
  // balance, modulo
  $overhead = $count % $groups;
  // for each group
  for ($i = 0; $i < $groups; ++$i) {
    // group offset, add 1 for each group that got a balance element
    $offset = ($i * $limit) + ($i < $overhead ? $i : $overhead);
    // length, add 1 if it is a group with balance element
    $length = $limit + ($i < $overhead ? 1 : 0);
    // copy slice from original array
    $result[] = array_slice($array, $offset, $length);
  }
  return $result;
}

$input = array('Item 1',  'Item 2',  'Item 3',  'Item 4',  'Item 5',  'Item 6', 'Item 7');
$grouped = array_group_elements($input, 3);
var_dump(
  array_map(
    function($group) {
      return implode(', ', $group);
    },
    $grouped
  )
);

輸出:

array(3) {
  [0]=>
  string(22) "Item 1, Item 2, Item 3"
  [1]=>
  string(14) "Item 4, Item 5"
  [2]=>
  string(14) "Item 6, Item 7"
}

函數 array_group_elements() 遍歷 $groups(3 次),而不是 $array(7 次)。

我有兩個不同方法的函數。

function restructureArray1($array, $x)
    {
    $size = sizeof($array);
    if ($size < $x)
        return array_chunk($array, 1) + array_fill(0, $x, array());
        // chunk by 1 element and add missing empty elements

    $big_row_length = (int) ($size / $x) + 1;
    $big_rows_chunk = array_splice($array, 0, $size % $x * $big_row_length);
    // $big_rows_chunk contains items with big rows
    // $array now contains items with small rows
    return array_merge(array_chunk($big_rows_chunk, $big_row_length), array_chunk($array, $big_row_length - 1));
    // chunk and merge
    }

function restructureArray2($array, $x)
    {
    $size = sizeof($array);
    $small_row_length = (int) ($size / $x);
    $big_row_count = $size % $x;
    for ($i = 0; $i < $x; ++$i)
        {
        $length = $small_row_length + (int) ($i < $big_row_count); // type juggling
        $return [] = array_splice($array, 0, $length);
        // $return[] contains one row
        // $array now contains rest of array
        }
    return $return;
    }

要獲得字符串數組的結果,您只需要array_map 即可

$x = 3;
$size = 7;
$array = range(1, $size);
$result1 = restructureArray1($array, $x);
$result2 = restructureArray2($array, $x);

var_dump(array_map(function($array)
            { return implode(', ', $array); }, $result2));

演示

文檔的相關鏈接: array_splicearray_chunkarray_merge

PS最短的解決方案


function restructureArray3($array, $x)
    {
    while($x)
        $return [] = array_splice($array, 0, ceil(sizeof($array) / $x--));
    return $return;
    }

演示

我提出了以下算法,可以在每行中保持正確數量的項目; 在每次迭代中,我們對剩余行數與剩余項目數的划分進行四舍五入:

$a = range(1,7);

$len = count($a);
$res = array();
$max = 3;

$i = 0;
while ($i < $len) {
        // divide the remaining number of items by the maximum rows allowed
        // this gives the width for the current row
        $width = ceil(($len - $i) / $max);

        $res[] = join(', ', array_slice($a, $i, $width));

        // adjust pointer and reduce the maximum
        $i += $width;
        --$max;
}

print_r($res);

演示

<?php
$source_array = array(
  'item 1',
  'item 2',
  'item 3',
  'item 4',
  'item 5',
  'item 6',
  'item 7',
  'item 8',
  'item 9',
  'item 10',
);


$k = 4;

// allocating cells
$allocated_cells_sizes = array();
$ik = 0;
foreach ($source_array as $value){
  if (! isset($allocated_cells_sizes[$ik])) $allocated_cells_sizes[$ik] = 0;
  $allocated_cells_sizes[$ik] ++;
  if (++$ik >= $k) $ik = 0;
}

// filling result array
$result = array();
foreach ($allocated_cells_sizes as $cells_sizes){
  $result[] = implode(', ', array_slice($source_array, 0, $cells_sizes));
  $source_array = array_slice($source_array, $cells_sizes, null);
}

print_r($result);

/**
 * Output
 * Array
    (
    [0] => item 1, item 2, item 3
    [1] => item 4, item 5, item 6
    [2] => item 7, item 8
    [3] => item 9, item 10
    )

 */

對於每個組,您需要計算適合每個段的最大項目數,因此我使用了 ceil(); 函數總是四舍五入。

輸入:

Array
(
    [0] => item1
    [1] => item2
    [2] => item3
    [3] => item4
    [4] => item5
    [5] => item6
    [6] => item7
)

功能:

function segment_array($array, $segment = '3'){

    // Count the items
    $count = count($array);

    // Create an array item for each segment
    for($i=0;$i<$segment;$i++){
        $offset += ($count - ($count - $chunk));
        $chunk = ceil(($count - $offset)/($segment - $i));
        $set[$i] = array_slice($array, $offset, $chunk);
        $new_array[] = implode(', ', $set[$i]);
    }

    return($new_array);
}

$segmented = segment_array($array, '3');

輸出:

Array
(
    [0] => item1, item2, item3
    [1] => item4, item5
    [2] => item6, item7
)

代碼:

$input = array('Item 1',  'Item 2',  'Item 3',  'Item 4',  'Item 5',  'Item 6',  'Item 7');
$height = 3;
$commonWidth = floor(count($input) / $height);
$remaining = count($input) % $height;
$i = 0;
for ($j = 0; $j < $height; $j++) {
    $width = $commonWidth + (0 < $remaining--);
    $output[] = implode(', ', array_slice($input, $i, $width));
    $i += $width;
}
print_r($output);

輸出:

Array
(
    [0] => Item 1, Item 2, Item 3
    [1] => Item 4, Item 5
    [2] => Item 6, Item 7
)

不知道是不是問題描述有誤,要求的結果其實是一個多維數組,而不是一個串連起來的數組。 在這種情況下,只需刪除對內爆的調用:

$input = array('Item 1',  'Item 2',  'Item 3',  'Item 4',  'Item 5',  'Item 6',  'Item 7');
$height = 3;
$commonWidth = floor(count($input) / $height);
$remaining = count($input) % $height;
$i = 0;
for ($j = 0; $j < $height; $j++) {
    $width = $commonWidth + (0 < $remaining--);
    $output[] = array_slice($input, $i, $width);
    $i += $width;
}
print_r($output);

輸出是:

Array
(
    [0] => Array
        (
            [0] => Item 1
            [1] => Item 2
            [2] => Item 3
        )

    [1] => Array
        (
            [0] => Item 4
            [1] => Item 5
        )

    [2] => Array
        (
            [0] => Item 6
            [1] => Item 7
        )
)

適用於任意數量的項目。 並更改任意數量的列,只需更改 $x 值。

<?php
    $arr = array('Item 1','Item 2','Item 3','Item 4','Item 5','Item 6', 'Item 7');
    $x = 3;
    $newArr = array();
    $j = 0;
    foreach($arr as $key=>$val){
        if($j == $x){
            $j = 0;
        }
        $newArr[$j][] = $val;
        $j++;
    }
    foreach($newArr as $key=>$val){
        $tempVal = implode(',', $val);
        $newArr[$key] = $tempVal;
    }
    print_r($newArr);
    ?>

另一種算法,因為據我了解問題是就地重組數組,因此在不創建臨時數組的情況下可以實現最佳效率。

<?php
function group_array(&$array, $parts = 3)
{
    $size = count($array);
    $length = floor($size / $parts);
    $remains = $size % $parts;
    $done = 0;
    for($i = 0; $i < $parts; ++$i)
    {
        $real_length = $length + ($i < $remains ? 1 : 0);
        $array[$i] = $array[$done];
        for($j = $done + 1; $j < min($done + $real_length, $size); ++$j)
            $array[$i] .= ', ' . $array[$j];
        $done += $real_length;
    }
    for($i = $size; $i >= $parts ; --$i)
        unset($array[$i]);
}

?>

測試用例#1:

<?php

$array = array("item 1", "item 2", "item 3", "item 4", "item 5", "item 6", "item 7");
group_array($array);

echo '<pre>' . print_r($array, true) . '</pre>';

?>

輸出:

Array
(
    [0] => item 1, item 2, item 3
    [1] => item 4, item 5
    [2] => item 6, item 7
)

測試用例#2:

<?php

$array = array("item 1", "item 2", "item 3", "item 4", "item 5", "item 6",
               "item 7", "item 8", "item 9", "item 10");
group_array($array);

echo '<pre>' . print_r($array, true) . '</pre>';

?>

輸出:

Array
(
    [0] => item 1, item 2, item 3, item 4
    [1] => item 5, item 6, item 7
    [2] => item 8, item 9, item 10
)

如果您對二維數組感到滿意,並且如果最后一行可以比其余所有行小得多,您會很高興,這里有一個單行:

function split_array1($orig_array, $parts = 1) {
    return array_chunk($orig_array,ceil(count($orig_array)/$parts));    
}

同樣的事情,將每個部分合並成字符串:

function split_array2($orig_array, $parts = 1) {
    $split = array_chunk($orig_array,ceil(count($orig_array)/$parts));
    foreach ($split as &$row) $row = join($row, ', ');
    return $split;
}

三個測試的輸出,分別有 7、8 和 9 個項目:

Array ( [0] => Item 1, Item 2, Item 3 [1] => Item 4, Item 5, Item 6 [2] => Item 7 ) 
Array ( [0] => Item 1, Item 2, Item 3 [1] => Item 4, Item 5, Item 6 [2] => Item 7, Item 8 ) 
Array ( [0] => Item 1, Item 2, Item 3 [1] => Item 4, Item 5, Item 6 [2] => Item 7, Item 8, Item 9 ) 

測試:

$input = array('Item 1',  'Item 2',  'Item 3',  'Item 4',  'Item 5',  'Item 6', 'Item 7', 'Item 8',  'Item 9');
for ($size=7; $size<=count($input); $size++){
    $output = split_array2(array_slice($input, 0, $size), 3);
    print_r($output);
    echo '<br>';
}

這將完全匹配您的示例:

function split_array3($orig_array, $parts = 1) {
    $count = count($orig_array);
    for ($i=0, $index=0; $i<$parts; $i++) {
        $size_of_sub = ceil(($count - $index) / ($parts-$i));
        $split[$i] = join(array_slice($orig_array, $index, $size_of_sub), ', ');
        $index += $size_of_sub;
    }
    return $split;
}

結果:

Array ( [0] => Item 1, Item 2, Item 3 [1] => Item 4, Item 5 [2] => Item 6, Item 7 ) 
Array ( [0] => Item 1, Item 2, Item 3 [1] => Item 4, Item 5, Item 6 [2] => Item 7, Item 8 ) 
Array ( [0] => Item 1, Item 2, Item 3 [1] => Item 4, Item 5, Item 6 [2] => Item 7, Item 8, Item 9 ) 

只是為了好玩,這里有一個使用遞歸的解決方案:

function recursive_split_array($orig_array, $num_sub_arrays = 1) {
    $size_of_sub = ceil(count($orig_array) / $num_sub_arrays);
    $split[0] = join(array_slice($orig_array, 0, $size_of_sub),', ');
    $split = array_merge( $split,
                          split_array(array_slice($orig_array, $size_of_sub,
                                                  count($orig_array)-$size_of_sub),$num_sub_arrays - 1));
    return $split;
}

對不起,它應該是評論,但我不能發表評論,也許是因為我的聲譽......

當您有一個包含 7 個元素的數組時,您知道將數組除以 3 還是必須找到除數?

編輯 1像這樣的東西?

$formatedAddress = array();
$divisor = 3;
$key = 0;
$counter =1;
foreach ($addressParts as $part)
{
    if(!empty($part){
        $formattedAddress[$key] = $part;
        if($counter != $divisor){
           $counter++;
        }else{
            $counter = 1;
            $key++;
        }
    }

}

編輯 2:

我發現了一些錯誤:

$formatedAddress = array();
$divisor = 3;
$key = 0;
$counter =1;
foreach ($addressParts as $part)
{
    if(!empty($part)){

    $formatedAddress[$key][] = $part;

    if($counter != $divisor){
       $counter++;
    }else{
        $counter = 1;
        $key++;
    }
    }
}
$source_array = array(
  'item 1',
  'item 2',
  'item 3',
  'item 4',
  'item 5',
  'item 6',
  'item 7',
  'item 8',
  'item 9',
  'item 10',
);

function reduce_array($input, $first_count = 3, $count = 2)
{
    $array_slice = array(array_slice($input, 0, $first_count));

    $array_chunk = array_chunk(array_slice($input, $first_count), $count);

    return array_merge($array_slice, $array_chunk);
}

$reduce_array = reduce_array($source_array); 

var_dump($reduce_array);

foreach($reduce_array as $array)
{
    var_dump(implode(',', $array));
}


Output:


array(5) {
  [0]=>
  array(3) {
    [0]=>
    string(6) "item 1"
    [1]=>
    string(6) "item 2"
    [2]=>
    string(6) "item 3"
  }
  [1]=>
  array(2) {
    [0]=>
    string(6) "item 4"
    [1]=>
    string(6) "item 5"
  }
  [2]=>
  array(2) {
    [0]=>
    string(6) "item 6"
    [1]=>
    string(6) "item 7"
  }
  [3]=>
  array(2) {
    [0]=>
    string(6) "item 8"
    [1]=>
    string(6) "item 9"
  }
  [4]=>
  array(1) {
    [0]=>
    string(7) "item 10"
  }
}
string(20) "item 1,item 2,item 3"
string(13) "item 4,item 5"
string(13) "item 6,item 7"
string(13) "item 8,item 9"
string(7) "item 10"
<?php

    $sample_array = array('item 1','item 2', 'itme 3','item 4', 'item 5','item 6','item 7', 'item 8','item 9','item 10',
        'item 11','item 12','item 13','item 14','item 15','item 16');

    restructure($sample_array,3);        

          function restructure($array ,$size)
           {
            $i=0;       
            while($i<= count($array))
             {
                $j=$i;
                $count = 0;
                while ($count<$size)
                {
                    if($j<count($array))
                    {
                     echo $array[$j]. " ";
                     $j++;
                    }
                         $count++;
                 }
                 echo '<br>';
                 $i=$i+$size;

             }

           }

    ?>

    <?php

試試這個:

function array_group($array, $X){
    $extra = count($array)%$X;
    $pre = array_splice($array, 0, $extra);
    $post = array_chunk($array, count($array)/$X);

    $post[0] = array_merge($pre, $post[0]);

    foreach ($post as &$key) {
        $key = implode(', ', $key);
    }
    return $post;
}

可以嗎?

$items = array('item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7');
array_unshift($items, '');
$chunkitems = array_chunk($items, 2);
$newitems = array_map(function($v){return implode(', ', $v);}, $chunkitems);
$first = ltrim(implode(', ', array(array_shift($newitems), array_shift($newitems))),', ');
array_unshift($newitems, $first);
print_r($newitems);

這看起來很簡潔:

function ReduceArray($input,$length)
{
    $count = count($input);

    // fill new array with new number of empty elements
    $newArray = array_fill(0,ceil($count/$length),"");

    for( $i = $count; $i > 0; $i--)
    {   
        // calculate index in new array to insert item
        $index = ceil($i / $length)-1;

        // we need a comma separator in this position if the array is empty
        $sep = ($newArray[$index] != "" ? "," : "");

        // insert into new array
        $newArray[$index] = array_pop($input) . $sep . $newArray[$index] ;
    }

    return $newArray;
}

是我對另一個非常非常相似的問題(幾乎重復)的回答的改編。

代碼:(演示

function custom_chunk($array, $maxrows) {
    $result = [];
    $size = sizeof($array);
    $columns = ceil($size / $maxrows);
    $fullrows = $size - ($columns - 1) * $maxrows;

    for ($i = 0; $i < $maxrows; ++$i) {
        $result[] = implode(', ', array_splice($array, 0, ($i < $fullrows ? $columns : $columns - 1)));
    }
    return $result;
}

$data = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7'];

var_export(custom_chunk($data, 3));

輸出:

array (
  0 => 'Item 1, Item 2, Item 3',
  1 => 'Item 4, Item 5',
  2 => 'Item 6, Item 7',
)

再一分錢,也許。 :-)

<?php

function restructure($x,$slots)
{
  $result=array();
  $count=count($x);

  $least=(int)($count/$slots);
  $excess=$count-$least*$slots;

  for($i=0;$i<($least+1)*$excess;$i+=$least+1)
    array_push($result,implode(", ",array_slice($x,$i,$least+1)));
  for(;$i<$count;$i+=$least)
    array_push($result,implode(", ",array_slice($x,$i,$least)));
  return $result;
}

if (PHP_SAPI==='cli') {

  $x=array(
  "item 1",
  "item 2",
  "item 3",
  "item 4",
  "item 5",
  "item 6",
  "item 7",
  );

  print_r(restructure($x,3));

}

這使得:

Array
(
    [0] => item 1, item 2, item 3
    [1] => item 4, item 5
    [2] => item 6, item 7
)

編輯:修復了@mickmackusa指出的錯誤。 https://3v4l.org/hIVfb

很好的問題+1。 我已經更動態地創建了解決方案。

  1. 由於用戶輸入可以是 1.....n 中的任何數字
  2. 要描述或更改的成員的最小分組
  3. 要描述或可以隨時更改的最大成員分組

這將是其他人相應地改變事物的優勢:

<?

//can n number of array items
$items = array('item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7');

//counting of total number of items
$total_items = count($items);

//item to find in array
$find_item = "item7";

//first item found key number
$key = array_search($find_item, $items);

//Splitting into two

//array with last found as item
$temp_output1 = array_slice($items, 0, $key+1); 

//items left
$temp_output2 = array_slice($items, $key+1, $total_items); 

//minimum number items to group
$minimum_group=2;

//Maximum Number of Grouped items
$maximum_group=4;

if ( $temp_output1 ) {
    //sending to group accordingly
    $output1 = do_slicing($temp_output1, $minimum_group, $maximum_group);
    print_r($output1);
}

if ( $temp_output2 ) {
    //sending to group accordingly
    $output2 = do_slicing($temp_output2, $minimum_group, $maximum_group);
    print_r($output2);
}


function do_slicing($temp_output = array(), $minimum_group, $maximum_group){
    $count = count($temp_output);

    //array is equal to min grouping
    if ( $count == $minimum_group){
        //Group them and return
        return by_grouping($temp_output, $minimum_group);
    }elseif ($count == $maximum_group){
        //if items equal to maximum then group them and return
        return by_grouping($temp_output, $maximum_group);
    }elseif ( ($count > $minimum_group) and ($count < $maximum_group)){
        return by_grouping($temp_output, count($temp_output));
    }elseif ($count == 1) {
        //if item is 1 print error or return from here
        return $temp_output;
    }else{
        //calculate the total number of groups available
        $item_slice_count = intval($count/$maximum_group);

        //Split them as grouped members
        $temp_slice = array_slice($temp_output, 0, 
                    ($item_slice_count*$maximum_group));

        //non group members
        $temp_slice2 = array_slice($temp_output, 
                    ($item_slice_count*$maximum_group), $count);

        //if there is no non group members
        if ( !$temp_slice2 ) {
            //combine them and return according to maximum grouping
            return by_grouping($temp_slice, $maximum_group);
        }else{
            if ( 
                (count($temp_slice2) === $minimum_group) or 
                (
                  (count($temp_slice2) > $minimum_group) and  
                  (count($temp_slice2) < 
                   $maximum_group)
                 ) 
             ){
                //if count of slice2 equal to minimum group then
                $a=by_grouping($temp_slice, $maximum_group);
                if ( 
                  (count($temp_slice2) > $minimum_group) and  
                  (count($temp_slice2) < 
                   $maximum_group)
                 ){
                    $b=by_grouping($temp_slice2, count($temp_slice2));
                }else{
                    $b=by_grouping($temp_slice2, $minimum_group);
                }
                return array_merge($a, $b);
            }elseif( count($temp_slice2) < $minimum_group ) {
                //if less then minimum group then
                //if total count is divisible with minimum group
                if ( ($count % $minimum_group ) == 0 ){
                    //return after clubbing according minimum group
                    return by_grouping($temp_output, $minimum_group);
                }else{
                    //Where last group is not equal to minimum group

                    //Minimum more needed to complete last slice
                    $minimum_needed = $minimum_group - count($temp_slice2);

                    //slice1 become
                    $slice1 = array_slice($temp_output, 0, (
                               ($item_slice_count-1)*$maximum_group));

                    //slice2 would be
                    $slice2 = array_slice($temp_output, (
                                      ($item_slice_count-1)*$maximum_group),
                                      ($maximum_group-$minimum_needed));

                    //slice 3 then
                    $slice3 = array_slice($temp_output, ( 
                               (($item_slice_count-1)*$maximum_group) + 
                              ($maximum_group-$minimum_needed)),
                               $count);

                    //if slice2 is greater or equal to minimum group then
                    if ( $slice2>=$minimum_group) {
                        $a=by_grouping($slice1, $maximum_group);
                        $b=array_merge($a, by_grouping($slice2,
                                      count($slice2)));
                        $c=by_grouping($slice3, $minimum_group);
                        return array_merge($b, $c);
                    }else{
                        die("This Situation doesn't reached any time");
                    }
                }
            }
        }
    }
}

//Grouping of members according to slices provided
function by_grouping($temp_slice, $group){
    $return = array();
    $temp = array_chunk($temp_slice, $group);
    foreach($temp as $a){
        $return[] = implode(', ', $a);
    }
    return $return;
}

?>

演示代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM