php - Group values of a flat array into sets of consecutive strings with the same leading characters - Stack Overflow

admin2025-04-18  3

I have a dynamic array, each group of lines start with a specific code "S10.G00.00", "S10.G00.01", "S10.G00.02" ...

The array may be like this:

array:20 [▼
  0 => "S10.G00.00.001,'www.mywebsite'"
  1 => "S10.G00.00.002,'Company name'"
  2 => "S10.G00.00.003,'v2.01'"
  3 => "S10.G00.01.001,'492484944'"
  4 => "S10.G00.01.002,'00029'"
  5 => "S10.G00.01.003,'First name'"
  6 => "S10.G00.01.004,'120 R CHARLES'"
  7 => "S10.G00.01.005,'92200'"
  8 => "S10.G00.02.001,'01'"
  9 => "S10.G00.02.002,'first name'"
  10 => "S10.G00.02.004,'[email protected]'"
  11 => "S10.G00.02.005,'0750000000'"
  12 => "S20.G00.05.001,'01'"
  13 => "S20.G00.05.002,'01'"
  14 => "S20.G00.05.003,'11'"
  15 => "S20.G00.05.004,'5'"
  16 => "S20.G00.05.010,'01'"
  17 => "S10.G00.01.001,'492484944'"
  18 => "S10.G00.01.002,'00029'"
  19 => "S10.G00.01.003,'Last name'"
]

I would like to select each group of successive lines that start with the same code (the first 10 characters) and put them into an associative array.

The associative array should be like this :

array:5 [▼
  0 => array:1 [▼
    "S10.G00.00" => array:3 [▼
      0 => "S10.G00.00.001,'www.mywebsite'"
      1 => "S10.G00.00.002,'Company name'"
      2 => "S10.G00.00.003,'v2.01'"
    ]
  ]
  1 => array:1 [▼
    "S10.G00.01" => array:5 [▼
      0 => "S10.G00.01.001,'492484944'"
      1 => "S10.G00.01.002,'00029'"
      2 => "S10.G00.01.003,'First name'"
      3 => "S10.G00.01.004,'120 R CHARLES'"
      4 => "S10.G00.01.005,'92200'"
    ]
  ]
  2 => array:1 [▼
    "S10.G00.02" => array:4 [▼
      0 => "S10.G00.02.001,'01'"
      1 => "S10.G00.02.002,'first name'"
      2 => "S10.G00.02.004,'[email protected]'"
      3 => "S10.G00.02.005,'0750000000'"
    ]
  ]
  3 => array:1 [▼
    "S10.G00.05" => array:5 [▼
      0 => "S20.G00.05.001,'01'"
      1 => "S20.G00.05.002,'01'"
      2 => "S20.G00.05.003,'11'"
      3 => "S20.G00.05.004,'5'"
      4 => "S20.G00.05.010,'01'"
    ]
  ]
  4 => array:1 [▼
    "S10.G00.01" => array:3 [▼
      0 => "S10.G00.01.001,'492484944'"
      1 => "S10.G00.01.002,'00029'"
      2 => "S10.G00.01.003,'Last name'"
    ]
  ]
]

I have a dynamic array, each group of lines start with a specific code "S10.G00.00", "S10.G00.01", "S10.G00.02" ...

The array may be like this:

array:20 [▼
  0 => "S10.G00.00.001,'www.mywebsite.com'"
  1 => "S10.G00.00.002,'Company name'"
  2 => "S10.G00.00.003,'v2.01'"
  3 => "S10.G00.01.001,'492484944'"
  4 => "S10.G00.01.002,'00029'"
  5 => "S10.G00.01.003,'First name'"
  6 => "S10.G00.01.004,'120 R CHARLES'"
  7 => "S10.G00.01.005,'92200'"
  8 => "S10.G00.02.001,'01'"
  9 => "S10.G00.02.002,'first name'"
  10 => "S10.G00.02.004,'[email protected]'"
  11 => "S10.G00.02.005,'0750000000'"
  12 => "S20.G00.05.001,'01'"
  13 => "S20.G00.05.002,'01'"
  14 => "S20.G00.05.003,'11'"
  15 => "S20.G00.05.004,'5'"
  16 => "S20.G00.05.010,'01'"
  17 => "S10.G00.01.001,'492484944'"
  18 => "S10.G00.01.002,'00029'"
  19 => "S10.G00.01.003,'Last name'"
]

I would like to select each group of successive lines that start with the same code (the first 10 characters) and put them into an associative array.

The associative array should be like this :

array:5 [▼
  0 => array:1 [▼
    "S10.G00.00" => array:3 [▼
      0 => "S10.G00.00.001,'www.mywebsite.com'"
      1 => "S10.G00.00.002,'Company name'"
      2 => "S10.G00.00.003,'v2.01'"
    ]
  ]
  1 => array:1 [▼
    "S10.G00.01" => array:5 [▼
      0 => "S10.G00.01.001,'492484944'"
      1 => "S10.G00.01.002,'00029'"
      2 => "S10.G00.01.003,'First name'"
      3 => "S10.G00.01.004,'120 R CHARLES'"
      4 => "S10.G00.01.005,'92200'"
    ]
  ]
  2 => array:1 [▼
    "S10.G00.02" => array:4 [▼
      0 => "S10.G00.02.001,'01'"
      1 => "S10.G00.02.002,'first name'"
      2 => "S10.G00.02.004,'[email protected]'"
      3 => "S10.G00.02.005,'0750000000'"
    ]
  ]
  3 => array:1 [▼
    "S10.G00.05" => array:5 [▼
      0 => "S20.G00.05.001,'01'"
      1 => "S20.G00.05.002,'01'"
      2 => "S20.G00.05.003,'11'"
      3 => "S20.G00.05.004,'5'"
      4 => "S20.G00.05.010,'01'"
    ]
  ]
  4 => array:1 [▼
    "S10.G00.01" => array:3 [▼
      0 => "S10.G00.01.001,'492484944'"
      1 => "S10.G00.01.002,'00029'"
      2 => "S10.G00.01.003,'Last name'"
    ]
  ]
]
Share edited Mar 14 at 21:41 mickmackusa 48.3k13 gold badges94 silver badges161 bronze badges Recognized by PHP Collective asked Jan 30 at 13:47 houshous 2,7092 gold badges30 silver badges73 bronze badges 1
  • Other pages which group 1d arrays by value prefix (but not by consecutive prefixes): Group array values by prefix and How to separate a php array items by prefix and Group a flat array by value prefix and populate an indexed array of indexed arrays and PHP Group array of postcodes by their 4 for letters PHP – mickmackusa Commented Mar 26 at 22:45
Add a comment  | 

3 Answers 3

Reset to default 4

All you need is a simple loop and to keep track of the previous 10th characters:

$result = [];
$previousKey = null;
$index = -1;

foreach ($arr as $item) {
    $currentKey = substr($item, 0, 10);

    if ($previousKey !== $currentKey) {
        $previousKey = $currentKey; 
        $index++;
    }
    
    $result[$index][$currentKey][] = $item;
}

demo

When the 10th first characters change, increment the index.

Instead of managing the current group's index in the result array and keeping track of previously encountered values, I prefer to accumulate grouped data in references which are only pushed into the result array once -- when a new group is required. Demo

$result = [];
foreach ($array as $v) {
    $prefix = substr($v, 0, 10);
    if (!isset($ref[$prefix])) {
        unset($ref);
        $result[] =& $ref[$prefix];
    }
    $ref[$prefix][$prefix][] = $v;
}
var_export($result);

Traditionally, I prefer array_reduce(), to iterate an array and produce a result with a potentially changed array size.

My script requires two static variables, one to manage the first-level index and one to remember the previous group. Demo

print_r(
    array_reduce(
        $input,
        static function ($carry, $item)
        {
            static $index, $previous;

            $group = substr($item, 0, 10);

            // increment the index conditionally on a new group
            $carry[$index += ($previous && $group !== $previous)]

            // memorize the group
            [$previous = $group][] = $item;

            // push the item
            return $carry;
        },
        [[]]
    )
);

If the input array is empty, an array containing a lone empty array will be returned by default.

转载请注明原文地址:http://anycun.com/QandA/1744915342a89426.html