Я пытаюсь свести ассоциативный массив к парам уникальных значений, при этом ключи - это буквы, которые нужно связать, а значения - их count()
s.
Каждая пара не может содержать одну и ту же букву дважды, например AA
или BB
.
Допускается более одного появления одной и той же пары.
например AC
, DC
, AC
, DC
все допустимы в результирующем массиве
Каждый раз, когда выбирается буква, связанный с ней номер уменьшается на единицу, пока ничего не остается, или
Любые нечетные / оставшиеся буквы следует пометить и не игнорировать, например Array([paired]=>Array(...) [unpaired]=>Array(...))
Пример ввода:
Array(
[A] => 8
[B] => 16
[C] => 15
[D] => 4
[E] => 1
)
Возможный выход:
[
'paired' => [
'BD', 'AE', 'BC', 'AC', 'BC', ...
],
'unpaired' => [
'C' => 4
]
]
Я бы предпочел, чтобы две уникальные буквы выбирались случайным образом, но если это слишком сложно, то результирующий массив должен быть легко shuffle()
- способным
Я пробовал различные комбинации array_reduce()
, array_map()
, array_walk()
, array_unique()
и т. Д., Даже груши Math_Combinatorics
, но все безрезультатно.
3 ответа
Вот функция, которая сгенерирует желаемые результаты. Он выполняет итерацию по массиву letters
, отфильтровывая буквы, которые были полностью использованы, до тех пор, пока не останется только одна буква, которая не используется. Затем список пар и неиспользованная буква возвращаются в виде массива:
function random_pairs($letters) {
$pairs = array();
$letters = array_filter($letters);
while (count($letters) > 1) {
$keys = array_keys($letters);
shuffle($keys);
list($letter1, $letter2) = array_slice($keys, 0, 2);
$pairs[] = "$letter1$letter2";
$letters[$letter1]--;
$letters[$letter2]--;
$letters = array_filter($letters);
}
return array('pairs' => $pairs, 'unpaired' => $letters);
}
Пример использования:
$letters = array('A' => 8, 'B' => 16, 'C' => 15, 'D' => 4, 'E' => 1);
print_r(random_pairs($letters));
Пример вывода:
Array
(
[pairs] => Array
(
[0] => CB
[1] => CE
[2] => CD
[3] => BD
[4] => CB
[5] => DC
[6] => AB
[7] => CA
[8] => DA
[9] => BC
[10] => BA
[11] => BA
[12] => AB
[13] => BA
[14] => BC
[15] => AB
[16] => BC
[17] => CB
[18] => CB
[19] => CB
[20] => CB
)
[unpaired] => Array
(
[C] => 2
)
)
Вот рекурсивная техника. Он использует array_rand()
для одновременного получения двух уникальных ключей. Если вам нужно, чтобы парные ключи были расположены случайным образом, вызовите для них shuffle()
. Я имею в виду, что shuffle()
может быть опущено в зависимости от ваших ожиданий.
Преимущество использования array_rand()
состоит в том, что array_keys()
не нужно вызывать, поскольку он возвращает случайные ключи.
Я специально разработал этот фрагмент, чтобы безоговорочно объявлять подмассив unpaired
- даже если он пуст.
Код: (Демо)
function randomPairs(array $letters, array $result = []) {
if (count($letters) < 2) {
$result['unpaired'] = $letters;
return $result;
}
$keys = array_rand($letters, 2);
shuffle($keys);
$result['paired'][] = $keys[0] . $keys[1];
--$letters[$keys[0]];
--$letters[$keys[1]];
return randomPairs(array_filter($letters), $result);
}
Без рекурсии: (Демо)
function randomPairs(array $letters): array {
$result['paired'] = [];
while (count($letters) > 1) {
$keys = array_rand($letters, 2);
shuffle($keys);
$result['paired'][] = $keys[0] . $keys[1];
--$letters[$keys[0]];
--$letters[$keys[1]];
$letters = array_filter($letters);
}
$result['unpaired'] = $letters;
return $result;
}
Предлагаю вам вот это:
Я только что видел ответ Ника, но это занимает 15 минут. Я пытаюсь xD. Я хочу опубликовать свой ответ: p
На основе функции "pickRandomValues" я сделал ее динамической, и вы также можете выбрать количество букв, которое хотите.
function pickRandom(&$array = [], $count = 1) {
$valuesFound = [];
if (count($array) >= $count) {
for ($i = 0; $i < $count; $i++) {
$index = rand(0, count($array) - 1);
$tmp = array_splice($array, $index, 1);
$valuesFound[] = $tmp[0];
}
}
return $valuesFound;
}
И ваш код тела
$tmpArr = [];
foreach ($a as $letter => $count) {
$t = [];
$tmpArr = array_merge($tmpArr, array_pad($t, $count, $letter));
}
$pairs = [];
while (count($tmpArr) >= $numberOfLetters) {
$pick = pickRandom($tmpArr, $numberOfLetters);
$pairs[] = implode($pick);
}
$finalArray = [
"paired" => $pairs,
"unpaired" => array_count_values($tmpArr)
];
Итак, это дает что-то вроде этого:
http://sandbox.onlinephpfunctions.com/code/3b143396b7267bd6029ff613746d6c047557a282
Похожие вопросы
Новые вопросы
php
PHP - это широко используемый высокоуровневый, динамический, объектно-ориентированный и интерпретируемый язык сценариев, в первую очередь предназначенный для серверной веб-разработки. Используется для вопросов о языке PHP.