Поиск в массиве нескольких значений в последовательном порядке

Возьмем заданные массивы:

// Original
array:14 [
  0 => "hello"
  1 => "i"
  2 => "like"
  3 => "cats"
  4 => "they're"
  5 => "cute"
  6 => "and"
  7 => "cuddly"
  8 => "you"
  9 => "know"
  10 => "well"
  11 => "i"
  12 => "love"
  13 => "cats"
]

// Sliced
array:6 [
  0 => "like"
  1 => "cats"
  2 => "they're"
  3 => "cute"
  4 => "and"
  5 => "cuddly"
]

Я хочу проверить массив original на предмет моих значений sliced и получить их исходные ключи. Это должно происходить только при совпадении последовательных значений.

В конечном итоге что-то вроде:

return array_keys_from_consec_values($original, $sliced);

// Result
array:14 [
  0 => 2
  1 => 3
  2 => 4
  3 => 5
  4 => 6
  5 => 7
]

Заметки

sliced не является результатом использования array_slice() в массиве original. В противном случае я бы использовал эту функцию и использовал бы параметр сохранения ключей.

Хочу избежать двусмысленности. Например, простой array_search для cats вернет ключ 3, но 13 также существует. Что может сбить функцию.

В случае, если какое-либо из значений sliced не существует в original (по порядку), должен быть возвращен пустой массив. Пример отказавшего массива sliced:

// Sliced
array:6 [
  0 => "like"
  1 => "cats"
  2 => "they're"
  3 => "cut3"
  4 => "and"
  5 => "cuddly"
]

Любые рекомендации, учли скорость ...

вы имеете в виду, что нужно только существовать в срезе?

Vasim Shaikh 01.05.2018 20:28

Я не понимаю, чего вы ожидаете от результата?

Vasim Shaikh 01.05.2018 20:33

оба являются массивом или строкой?

Vasim Shaikh 01.05.2018 20:34

что ты уже испробовал?

Spoody 01.05.2018 20:40

Что вы имеете в виду под происходит последовательное совпадение значений? ОП вам нужно быть более отзывчивым ...

Spoody 01.05.2018 20:45

если все значения в sliced существуют в original и в порядке (рядом друг с другом и по возрастанию), то верните ключи из original на основе совпадающих значений ... проверьте первую часть моего вопроса ...

Luka 01.05.2018 20:46

Я до сих пор не совсем понял, проверьте свой ответ (и обновите свой вопрос тем, что вы пробовали до сих пор)

Spoody 01.05.2018 20:48

"Нарезанный" массив исходит из array_slice()? Если это так, у функции есть возможность сохранить клавиши во время нарезки.

salathe 01.05.2018 20:53

Это не так, смотрите обновленные.

Luka 02.05.2018 11:52

Вы сдались ???

AbraCadaver 04.06.2018 17:22

Нет, я ответил на свой вопрос. См. Принятый ответ.

Luka 04.06.2018 17:39
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
11
82
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Насколько я понял, вы хотите получить индекс из массива $original на основе значений в $slice, вы можете использовать функции array_flip() и array_unique():

function array_keys_from_consec_values($original, $slice){
    // Get rid of duplicates and flip the keys with the values
    $index = array_unique($original);
    $index = array_flip($index);

    $result = [];

    // Loop through the slice
    foreach($slice as $key => $value){
        // Check if the value exists in the indexed array
        if (!isset($index[$value])){
            // Return an empty array
            return array();
        }
        // And get the key from the flipped array
        $result[$key] = $index[$value];
    }

    return $result;
}

var_dump(array_keys_from_consec_values($original, $slice));

Это даст:

array (size=6)
  0 => int 2
  1 => int 3
  2 => int 4
  3 => int 5
  4 => int 6
  5 => int 7

Да, это почти готово, но моя самая большая проблема - это неясности. На самом деле нам нужен первый появляющийся ключ cats (2). Я полагаю, тогда мы могли бы пойти дальше и отключить его ... так что мы получим 13 при следующем звонке.

Luka 01.05.2018 20:51

Думаю, мы на правильном пути, я приму это, потому что это хорошее усилие, и завтра у меня будет еще одна игра.

Luka 01.05.2018 20:54

Это работает с данными вашего примера и может быть достаточно хорошим:

$r = array_keys(array_unique(array_intersect($o, $s)));

Если нет, поскольку у вас есть срез:

if (($k = array_search($s[0], $o)) === false ||
   array_values($r = array_slice($o, $k, count($s), true)) != $s) {
    $r = [];
}
  • Найдите первый ключ оригинала из первого значения среза
  • Вырезать из оригинала (с сохранением ключей) и сравнить с ломтиком

Для вашего примера это дает:

Array
(
    [2] => like
    [3] => cats
    [4] => they're
    [5] => cute
    [6] => and
    [7] => cuddly
)

Я вижу после того, что вы хотите получить ключи:

$r = array_values(array_flip($r));

Если фрагмент является фактическим array_slice из оригинала, то передайте true в качестве четвертого параметра, чтобы сохранить ключи.

Хорошо, я сыграю. Срез массива, если он не используется в исходном массиве, поэтому нельзя использовать функцию и ее параметр сохранения ключей.

Luka 02.05.2018 10:13
Ответ принят как подходящий

Люди, приложившие усилия, я признаю, что просьбу было немного сложно объяснить - поэтому я не получил именно то, что искал. Я понял, что мне нужен был array_search, который возвращает несколько ключей при последовательном нахождении игл. Я пошел дальше и сам сделал функцию:

/**
 * Search for consecutive needles in haystack and return the corresponding keys.
 *
 * @param array $needles => Array values.
 * @param array $haystack => Array to search.
 * @param int $searchDirection => [0] (forwards) | [1] (backwards).
 * @return array
 */
function array_search_all_consec(array $needles, array $haystack, $searchDirection = 0)
{
    $needlesInScope = array_values($needles); // Keys not relevant, reset them.
    $haystackInScope = $haystack;

    if (in_array(reset($needlesInScope), $keys = array_keys($haystackInScope))) {
        $needlesLength = count($needlesInScope);

        foreach (($searchDirection == 0 ? $keys : array_reverse($keys)) as $offset) {
            $length = $offset + $needlesLength;
            $sliced = array_slice($haystackInScope, $offset, $length);

            if (empty(array_diff_assoc($needlesInScope, $sliced))) {
                return range($offset, $length - 1);
            }
        }
    }

    return [];
}

Тест 1

$o = [
    0 => "hello",
    1 => "i",
    2 => "like",
    3 => "cats",
    4 => "they",
    5 => "cute",
    6 => "and",
    7 => "cuddly",
    8 => "you",
    9 => "know",
    10 => "well",
    11 => "i",
    12 => "love",
    13 => "cats",
];

$s = [
    "i",
    "love",
    "cats",
];

return array_search_all_consec($s, $o);

// Result
array(3) {
  [0] =>
  int(11)
  [1] =>
  int(12)
  [2] =>
  int(13)
}

Тест 2

$s = [
    "i",
    "like",
    "cats",
];

return array_search_all_consec($s, $o);

// Result
array(3) {
  [0] =>
  int(1)
  [1] =>
  int(2)
  [2] =>
  int(3)
}

Тест 3

$s = [
    "i",
    "lov3",
    "cats",
];

return array_search_all_consec($s, $o);

// Result
array(0) {
}

Тест 4

$s = [
    "cats",
    "i",
    "love",
];

return array_search_all_consec($s, $o);

// Result
array(0) {
}

Тест 5

$s = [
    "i",
    "love",
    "cats",
    "blah",
];

return array_search_all_consec($s, $o);

// Result
array(0) {
}


So there you have it. If anyone can improve the efficiency of the function please do contribute!

Другие вопросы по теме