Найдите элемент внутри массива PHP с группировкой чисел

#php #arrays

Вопрос:

У меня есть длинный многомерный массив с группами чисел, насчитывающими до 100 … Например:

 $list = ( 
  array('1-4','first'), 
  array('5-7','next'),
  array('8-10','third group'), 
  array('11-12','another group'),
  /* ... keep going up to 100 */
  array('94-97','almost done'), 
  array('98-100','first')
);
 

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

 $num = rand(1,100);
 

Я хотел бы знать, как я буду получать#, связанный внутри массива. Итак, если бы я выкатил 3, я мог бы получить первый ключ массива (1-4) и иметь возможность распечатать «первый» …. или если бы я выкатил 97, я бы получил ключ от 2-го до последнего для «почти готово» (94-97). Есть ли быстрый способ сделать это?

Спасибо

Комментарии:

1. 1. Используйте цикл для повторения. 2. Используйте explode() для разбора строки. 3. if() 4. return или break .

Ответ №1:

Вы могли бы сделать что-то подобное, если структура $list гарантирована:

  $randomRoll = rand(1,100);
 array_walk($list, function($ar) use ($randomRoll){
    $nums = explode('-', $ar[0]);
    (int) $lower = $nums[0];
    (int) $upper = $nums[1];
    if (($randomRoll >= $lower) amp;amp; ($randomRoll <= $upper))
    {
        print($ar[1]); 
    }
});
 

Комментарии:

1. В этом ответе отсутствует его образовательное объяснение.

Ответ №2:

Вы можете упростить свой массив поиска до ассоциативного, так как в нем нет пробелов от 1 до 100. Другими словами, каждое случайное число попадет в одну из известных групп, определив наибольшее число, которое меньше или равно.

Не используйте никаких функциональных итераторов (например array_filter() , или array_walk() ), потому что они будут безоговорочно повторять весь массив поиска. Вместо этого используйте foreach() и break как можно скорее-это наиболее эффективно.

Код: (Демо)

 $list = [ 
  4 => 'first', // 1 - 4
  7 => 'next',  // 5 = 7
  10 => 'third group', // 8 - 10
  12 => 'another group', // 11, 12
  95 => 'huge chunk', // 13 - 95
  97 => 'almost done', // 96, 97
  100 => 'first' // 98 - 100
];

$num = rand(1, 100);
foreach ($list as $key => $group) {
    // echo "$num vs $keyn";
    if ($num <= $key) {
        break;                   // don't iterate anymore after finding group
    }
}
echo "Num = $num, Group = $group";
 

Комментарии:

1. Предложенный ассоциативный массив в основном предотвращает возникновение перекрытий или пробелов. Голос за это. Учитывая небольшое количество записей, для меня аргумент эффективности относится к области микрооптимизации.

2. Это самый простой, самый лаконичный, точный и ресурсосберегающий метод, который я могу придумать. Это то, что я бы использовал профессионально.

Ответ №3:

Я сделал следующее… и, похоже, это работает. Если у кого-нибудь есть советы по очистке кода, дайте мне знать… Спасибо…

 $dieroll = rand(1,100); // Final Roll
$numarr = array(); $j=0;
foreach ($list as $k => $v) {
    $strTr = $v[0];
    $nums2arr = explode("-", $strTr);
    for($i=$nums2arr[0]; $i<=$nums2arr[1]; $i  ) {
        $numarr[] = $j;
    }
    $j  ;
}

$roll = $list[$numarr[$dieroll-1]][1];  
 

Комментарии:

1. В этом ответе отсутствует его образовательное объяснение.

Ответ №4:

Это решение использует array_filter. В результате снова получается 2-мерный массив с элементами, которые удовлетворяют условию функции фильтра.

 $filter = function($a) use($find){
  list($low,$up) = explode('-',$a[0]);
  return $find >= $low AND $find <= $up; 
};
$arr = array_filter($list, $filter);
 

полный пример:

 $list = [ 
  ['1-4','first'], 
  ['5-7','next'],
  ['8-10','third group'], 
  ['11-12','another group'],
  /* ... keep going up to 100 */
  ['94-97','almost done'], 
  ['98-100','first']
];

//for a test is better to use a fix number
$find = 9;  

$filter = function($a) use($find){
  list($low,$up) = explode('-',$a[0]);
  return $find >= $low AND $find <= $up; 
};
$arr = array_filter($list, $filter);

echo 'Label: '.reset($arr)[1]."<br>n";
echo 'Area: '.reset($arr)[0]."<br>n";
echo 'Array-Key: '.key($arr)."<br>n";
 

Выход:

 Label: third group
Area: 8-10
Array-Key: 2
 

Начиная с PHP 8.0, для этого также возможны решения с соответствием:

 $num = rand(1, 100);

$group = match(true) {
  $num <= 4 => 'first',
  $num <= 7 => 'next',
  $num <= 10 => 'third group',
  $num <= 12 => 'another group',
  $num <= 95 => 'huge chunk',
  $num <= 97 => 'amost done',
  $num <= 100 => 'first',
};

echo "Num = $num, Group = $group";