PHP - отримати всі ключі з масиву, що починаються з певного рядка


84

У мене є масив, який виглядає так:

array(
  'abc' => 0,
  'foo-bcd' => 1,
  'foo-def' => 1,
  'foo-xyz' => 0,
  // ...
)

Як я можу отримати лише ті елементи, які починаються з foo-?


3
Наявність масиву з такими префіксами є запахом коду. Витягніть ці значення в об'єкт, що містить ці значення, або, принаймні, вкажіть префікс на масив і додайте до нього значення.
Гордон,

Відповіді:


20
$arr_main_array = array('foo-test' => 123, 'other-test' => 456, 'foo-result' => 789);

foreach($arr_main_array as $key => $value){
    $exp_key = explode('-', $key);
    if($exp_key[0] == 'foo'){
         $arr_result[] = $value;
    }
}

if(isset($arr_result)){
    print_r($arr_result);
}

18
Перш ніж приймати це рішення, краще підібрати наведене нижче. Ніколи не використовуйте функції масиву там, де буде достатньо простої функції рядка. Функції рядків набагато швидші. Це буде «відставати» від великих масивів.
Martijn

2
Я не бачу сенсу вибухувати ключі масиву в масиви. Вони є рядками, і оригінальне запитання просто задає питання про префікс рядка. Крім того, OP запитує "елементи", а не просто значення, тому числово індексований результат буде марним - тут явно важливі ключі, значення мають (імовірно) анонімні прапори 1/0.
Джейсон

126

Функціональний підхід:

Виберіть array_filter_keyякусь функцію з коментарів на http://php.net/array_filter або напишіть свою власну. Тоді ви могли зробити:

$array = array_filter_key($array, function($key) {
    return strpos($key, 'foo-') === 0;
});

Процедурний підхід:

$only_foo = array();
foreach ($array as $key => $value) {
    if (strpos($key, 'foo-') === 0) {
        $only_foo[$key] = $value;
    }
}

Процедурний підхід з використанням об'єктів:

$i = new ArrayIterator($array);
$only_foo = array();
while ($i->valid()) {
    if (strpos($i->key(), 'foo-') === 0) {
        $only_foo[$i->key()] = $i->current();
    }
    $i->next();
}

20
Примітка. PHP 5.6 додає прапор ARRAY_FILTER_USE_KEY array_filter(), який ви можете використовувати замість надання власної array_filter_key()функції.
Джейсон

4
Чи можете ви просто додати функцію array_filter_key до свого прикладу? Я постійно отримував помилку, і мені довелося перечитати вашу публікацію кілька разів, перш ніж визнати свою помилку. Неважко просто опублікувати код, зберегти клік і заощадити комусь час на усунення несправностей. Дякую.
Chris Sprague

38

Ось як би я це зробив, хоча я не можу дати вам більш ефективної поради, перш ніж зрозуміти, що ви хочете зробити з цінностями, які ви отримуєте.

$search = "foo-";
$search_length = strlen($search);
foreach ($array as $key => $value) {
    if (substr($key, 0, $search_length) == $search) {
        ...use the $value...
    }
}

2
Ви також можете використовувати:foreach ($array as $key => $value) { if (0 === strpos($key, 'foo-')) { ...use the $value... } }
Яго

"4" тут потрібно відрегулювати відповідно до довжини "foo-".
Джейсон

21

Просто я використовував array_filterфункцію для досягнення рішення наступним чином

<?php

$input = array(
    'abc' => 0,
    'foo-bcd' => 1,
    'foo-def' => 1,
    'foo-xyz' => 0,
);

$filtered = array_filter($input, function ($key) {
    return strpos($key, 'foo-') === 0;
}, ARRAY_FILTER_USE_KEY);

print_r($filtered);

Вихідні дані

Array
(
    [foo-bcd] => 1
    [foo-def] => 1
    [foo-xyz] => 0
)

Для прямої перевірки https://3v4l.org/lJCse


1
Зверніть увагу, що для цього потрібен принаймні PHP 5.6.0 (через використання константи ARRAY_FILTER_USE_KEY). У попередніх версіях ви можете використовувати: [код]
Netsurfer

20

З PHP 5.3 ви можете використовувати preg_filterфункцію: тут

$unprefixed_keys = preg_filter('/^foo-(.*)/', '$1', array_keys( $arr ));

// Result:
// $unprefixed_keys === array('bcd','def','xyz')

14
foreach($arr as $key => $value)
{
   if(preg_match('/^foo-/', $key))
   {
        // You can access $value or create a new array based off these values
   }
}

3
У цьому випадку регулярний вираз насправді не потрібен. Метод substr трохи ефективніший
jfoucher

2
@jfoucher: Це правда, однак особисто це легше читати.
Тім Купер

2
Він може бути більш гнучким, але коштує того, що потрібно уникати спеціальних символів преґ, якщо ви не хочете виконувати збіг із регулярним виразом. Тому використовуйте з обережністю. Я б запропонував використовувати РЕ лише в тому випадку, якщо Вам потрібні РЕ.
Джейсон

7

Модифікація функціонального підходу erisco ,

array_filter($signatureData[0]["foo-"], function($k) {
    return strpos($k, 'foo-abc') === 0;
}, ARRAY_FILTER_USE_KEY);

це спрацювало для мене.


Будь-яка різниця у продуктивності чи корисності порівняно з версією array_filter_key, наданою @erisco?
Джеффрі Жираф

Ні. Я думаю, різниці у продуктивності не повинно бути. @MaciekSemik
Keyur

1
Це основна функція PHP, тому їй слід надавати перевагу.
Джеремі Джон

3

На додаток до відповіді @Suresh Velusamy вище (яка потребує принаймні PHP 5.6.0), ви можете використовувати наступне, якщо ви користуєтесь попередньою версією PHP:

<?php

$input = array(
    'abc' => 0,
    'foo-bcd' => 1,
    'foo-def' => 1,
    'foo-xyz' => 0,
);

$filtered = array_filter(array_keys($input), function($key) {
    return strpos($key, 'foo-') === 0;
});

print_r($filtered);

/* Output:
Array
(
    [1] => foo-bcd
    [2] => foo-def
    [3] => foo-xyz
)
// the numerical array keys are the position in the original array!
*/

// if you want your array newly numbered just add:
$filtered = array_values($filtered);

print_r($filtered);

/* Output:
Array
(
    [0] => foo-bcd
    [1] => foo-def
    [2] => foo-xyz
)
*/

Зверніть увагу (або принаймні для мене), що це повертає лише відповідні ключі масиву. Відповідь нижче @ suresh-velusamy витягує фактичний масив із вихідною $key => $valueпарою. Це зазначено у результатах цієї відповіді, але ще не було згадано явно
Марті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.