Как найти первое вхождение элемента в массив

Учитывая отсортированный целочисленный массив, найдите индекс первого или последнего вхождения заданного числа. Если элемент отсутствует в массиве, также сообщите об этом.

Например,

Input:

 
nums = [2, 5, 5, 5, 6, 6, 8, 9, 9, 9]
target = 5

 
Output:

 
The first occurrence of element 5 is located at index 1
The last occurrence of element 5 is located at index 3

 
 
Input:

 
nums = [2, 5, 5, 5, 6, 6, 8, 9, 9, 9]
target = 4

 
Output:

 
Element not found in the array

Потренируйтесь в этой проблеме

Простым решением было бы запустить линейный поиск в массиве и вернуть первое или последнее вхождение данного элемента. Проблема с этим подходом заключается в том, что его временная сложность в наихудшем случае равна O(n), куда n это размер ввода. Это решение также не использует тот факт, что ввод отсортирован. Мы можем легко решить эту проблему в O(log(n)) время, изменив алгоритм бинарного поиска.

Поиск первого вхождения элемента

Стандартный бинарный поиск завершается, как только найдено любое вхождение заданного целевого элемента. Чтобы найти первое вхождение данного элемента, измените двоичный поиск, чтобы он продолжал поиск даже при обнаружении целевого элемента. Вместо этого обновите результат до mid и искать влево (в сторону более низких индексов), т. е. модифицировать наше пространство поиска, регулируя высокое значение до mid-1 при нахождении цели в середине индекса.

Ниже приведена программа на C, Java и Python, которая демонстрирует это:

C

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

#include <stdio.h>

// Функция для поиска первого вхождения заданного числа в отсортированном массиве целых чисел

int findFirstOccurrence(int nums[], int n, int target)

{

    // область поиска nums[low…high]

    int low = 0, high = n 1;

    // инициализируем результат на -1

    int result = 1;

    // цикл до тех пор, пока пространство поиска не будет исчерпано

    while (low <= high)

    {

        // находим среднее значение в пространстве поиска и сравниваем его с целевым

        int mid = (low + high)/2;

        // если цель обнаружена, обновить результат и

        // поиск влево (нижние индексы)

        if (target == nums[mid])

        {

            result = mid;

            high = mid 1;

        }

        // если цель меньше среднего элемента, отбрасываем правую половину

        else if (target < nums[mid]) {

            high = mid 1;

        }

        // если цель больше среднего элемента, отбрасываем левую половину

        else {

            low = mid + 1;

        }

    }

    // вернуть самый левый индекс или -1, если элемент не найден

    return result;

}

int main(void)

{

    int nums[] = {2, 5, 5, 5, 6, 6, 8, 9, 9, 9};

    int n = sizeof(nums)/sizeof(nums[0]);

    int target = 5;

    int index = findFirstOccurrence(nums, n, target);

    if (index != 1)

    {

        printf(«The first occurrence of element %d is located at index %d»,

                target, index);

    }

    else {

        printf(«Element not found in the array»);

    }

    return 0;

}

Скачать  Выполнить код

результат:

The first occurrence of element 5 is located at index 1

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

class Main

{

    // Функция для поиска первого вхождения заданного числа

    // в отсортированном целочисленном массиве

    public static int findFirstOccurrence(int[] nums, int target)

    {

        // область поиска nums[left…right]

        int left = 0;

        int right = nums.length 1;

        // инициализируем результат на -1

        int result = 1;

        // цикл до тех пор, пока пространство поиска не будет исчерпано

        while (left <= right)

        {

            // находим среднее значение в пространстве поиска и сравниваем его с целевым

            int mid = (left + right) / 2;

            // если цель обнаружена, обновить результат и

            // поиск влево (нижние индексы)

            if (target == nums[mid])

            {

                result = mid;

                right = mid 1;

            }

            // если цель меньше среднего элемента, отбрасываем правую половину

            else if (target < nums[mid]) {

                right = mid 1;

            }

            // если цель больше среднего элемента, отбрасываем левую половину

            else {

                left = mid + 1;

            }

        }

        // вернуть самый левый индекс или -1, если элемент не найден

        return result;

    }

    public static void main(String[] args)

    {

        int[] nums = {2, 5, 5, 5, 6, 6, 8, 9, 9, 9};

        int target = 5;

        int index = findFirstOccurrence(nums, target);

        if (index != 1)

        {

            System.out.println(«The first occurrence of element « + target +

                            » is located at index « + index);

        }

        else {

            System.out.println(«Element not found in the array»);

        }

    }

}

Скачать  Выполнить код

результат:

The first occurrence of element 5 is located at index 1

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

# Функция поиска первого вхождения заданного числа

# в отсортированном списке целых чисел

def findFirstOccurrence(nums, target):

    # пространство поиска nums[left…right]

    (left, right) = (0, len(nums) 1)

    # инициализирует результат значением -1

    result = 1

    # Цикл # до тех пор, пока пространство поиска не будет исчерпано

    while left <= right:

        # находит среднее значение в пространстве поиска и сравнивает его с целевым

        mid = (left + right) // 2

        #, если цель обнаружена, обновить результат и

        # поиск влево (нижние индексы)

        if target == nums[mid]:

            result = mid

            right = mid 1

        #, если цель меньше среднего элемента, отбросить правую половину

        elif target < nums[mid]:

            right = mid 1

        #, если цель больше среднего элемента, отбросить левую половину

        else:

            left = mid + 1

    # возвращает самый левый индекс или -1, если элемент не найден

    return result

if __name__ == ‘__main__’:

    nums = [2, 5, 5, 5, 6, 6, 8, 9, 9, 9]

    target = 5

    index = findFirstOccurrence(nums, target)

    if index != 1:

        print(f‘The first occurrence of element {target} is located at index {index}’)

    else:

        print(‘Element found not in the list’)

Скачать  Выполнить код

результат:

The first occurrence of element 5 is located at index 1

Поиск последнего вхождения элемента

Чтобы найти последнее вхождение элемента, измените стандартный двоичный поиск, чтобы он продолжал поиск даже при обнаружении цели. Вместо этого обновите результат до mid и продолжим поиск вправо (в направлении более высоких индексов), т. е. модифицируем наше пространство поиска, изменив низкие значения на mid+1 при нахождении цели в середине индекса.

Ниже приведена реализация C, Java и Python, основанная на приведенной выше идее:

C

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

#include <stdio.h>

// Функция для поиска последнего вхождения заданного числа в отсортированном массиве целых чисел

int findLastOccurrence(int nums[], int n, int target)

{

    // область поиска nums[low…high]

    int low = 0, high = n 1;

    // инициализируем результат на -1

    int result = 1;

    // цикл до тех пор, пока пространство поиска не будет исчерпано

    while (low <= high)

    {

        // находим среднее значение в пространстве поиска и сравниваем его с целевым

        int mid = (low + high)/2;

        // если цель обнаружена, обновить результат и

        // поиск вправо (более высокие индексы)

        if (target == nums[mid])

        {

            result = mid;

            low = mid + 1;

        }

        // если цель меньше среднего элемента, отбрасываем правую половину

        else if (target < nums[mid]) {

            high = mid 1;

        }

        // если цель больше среднего элемента, отбрасываем левую половину

        else {

            low = mid + 1;

        }

    }

    // вернуть самый левый индекс или -1, если элемент не найден

    return result;

}

int main(void)

{

    int nums[] = {2, 5, 5, 5, 6, 6, 8, 9, 9, 9};

    int n = sizeof(nums)/sizeof(nums[0]);

    int target = 5;

    int index = findLastOccurrence(nums, n, target);

    if (index != 1)

    {

        printf(«The last occurrence of element %d is located at index %d»,

                target, index);

    }

    else {

        printf(«Element not found in the array»);

    }

    return 0;

}

Скачать  Выполнить код

результат:

The last occurrence of element 5 is located at index 3

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

class Main

{

    // Функция для поиска последнего вхождения заданного числа

    // в отсортированном целочисленном массиве

    public static int findLastOccurrence(int[] nums, int target)

    {

        // область поиска nums[left…right]

        int left = 0;

        int right = nums.length 1;

        // инициализируем результат на -1

        int result = 1;

        // цикл до тех пор, пока пространство поиска не будет исчерпано

        while (left <= right)

        {

            // находим среднее значение в пространстве поиска и сравниваем его с целевым

            int mid = (left + right) / 2;

            // если цель обнаружена, обновить результат и

            // поиск вправо (более высокие индексы)

            if (target == nums[mid])

            {

                result = mid;

                left = mid + 1;

            }

            // если цель меньше среднего элемента, отбрасываем правую половину

            else if (target < nums[mid]) {

                right = mid 1;

            }

            // если цель больше среднего элемента, отбрасываем левую половину

            else {

                left = mid + 1;

            }

        }

        // вернуть самый левый индекс или -1, если элемент не найден

        return result;

    }

    public static void main(String[] args)

    {

        int[] nums = {2, 5, 5, 5, 6, 6, 8, 9, 9, 9};

        int target = 5;

        int index = findLastOccurrence(nums, target);

        if (index != 1)

        {

            System.out.println(«The last occurrence of element « + target +

                    » is located at index « + index);

        }

        else {

            System.out.println(«Element not found in the array»);

        }

    }

}

Скачать  Выполнить код

результат:

The last occurrence of element 5 is located at index 3

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

# Функция поиска последнего вхождения заданного числа в отсортированном списке целых чисел

def findLastOccurrence(nums, target):

    # пространство поиска nums[left…right]

    (left, right) = (0, len(nums) 1)

    # инициализирует результат значением -1

    result = 1

    # Цикл # до тех пор, пока пространство поиска не будет исчерпано

    while left <= right:

        # находит среднее значение в пространстве поиска и сравнивает его с целевым

        mid = (left + right) // 2

        #, если цель обнаружена, обновить результат и

        # поиск вправо (более высокие индексы)

        if target == nums[mid]:

            result = mid

            left = mid + 1

        #, если цель меньше среднего элемента, отбросить правую половину

        elif target < nums[mid]:

            right = mid 1

        #, если цель больше среднего элемента, отбросить левую половину

        else:

            left = mid + 1

    # возвращает самый левый индекс или -1, если элемент не найден

    return result

if __name__ == ‘__main__’:

    nums = [2, 5, 5, 5, 6, 6, 8, 9, 9, 9]

    target = 5

    index = findLastOccurrence(nums, target)

    if index != 1:

        print(f‘The last occurrence of element {target} is located at index {index}’)

    else:

        print(‘Element found not in the list’)

Скачать  Выполнить код

результат:

The last occurrence of element 5 is located at index 3

Временная сложность приведенных выше решений равна O(log(n)) и не требует дополнительного места.

 
Упражнение:

1. Напишите рекурсивную версию приведенных выше решений.

2. Проверьте, встречается ли данное целое число больше, чем n/2 раз в отсортированном массиве.

 
Использованная литература:

lets say i have an array A in non-descending order like this

A = [0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 500, 600]

My question is: how to find the first occurence (index) of an element equal or greather (if 4 is not present) than 4?

O(n) solution is easy, i would like to have something faster.
Probably binary search, but have no idea how to modify it.

Бинарный поиск

Дан массив из nn элементов, упорядоченный в порядке неубывания, и mm запросов: найти первое и последнее вхождение числа в массив.

Входные данные:

В первой строке содержится одно число n – размер массива (1≤n≤100000).

Во второй строке находится n чисел в порядке неубывания – элементы массива.

В третьей строке находится число m – количество запросов.

В последней строке находится m чисел – запросы.

Выходные данные:

Для каждого запроса выведите в отдельной строке номер первого и последнего вхождения этого числа в массив. Если числа в массиве нет, выведите -1 -1.

STDIN:

5

1 1 2 2 2

3

1 2 3

STDOUT:

1 2

3 5

-1 -1

Я не совсем понимаю как проверять эти запросы.

задан 20 окт 2022 в 8:47

Hobble's user avatar

HobbleHobble

415 бронзовых знаков

5

Ваша функция бинарного немного неправильна…

  1. По условию задачи вам нужно искать диапазон вхождения числа в массив. А вы возвращаете один индекс. Возвращайте пару или объект своей структуры с 2-мя значениями. Также, возвращать false нельзя, т.к. false == 0, а 0 — легитимный индекс ответа, т.е. искомое число может находиться по индексу 0.
  2. Параметр middle вообще не используется внутри функции, зачем было его передавать? Вы взяли определение от рекурсивной функции, а реализацию сделали циклическую. Также для вашей задачи не нужно начало и конец массива, нужно только количество элементов (размер массива). А т.к. у вас c++ и можно воспользоваться vector<int> для хранения, то и размер можно не передавать.
// вместо 
int BinSearch (int numb_to_find, int m[], int start, int end, int middle) {}
// получится
pair<int, int> BinSearch (int numb_to_find, vector<int>&m) {}
  1. В функцию вы передаете первое и последнее число, содержащееся в массиве. А надо вообще-то передавать индексы. А так у вас будет неопределенное поведение, связанное с выходом за границы массива. А в массиве могут быть и отрицательные числа!
int result = BinSearch(find, m, m[0], m[n-1], 0); // в качестве индексов передаются числа
int BinSearch () {
    while (start <= end) {
        if (m[middle] == numb_to_find) {} // которые используются как индексы
}

ответ дан 20 окт 2022 в 9:55

DmitryK's user avatar

DmitryKDmitryK

4,4961 золотой знак5 серебряных знаков19 бронзовых знаков

Если вам нужно самостоятельно реализовать бинарный поиск, то нужно воспользоваться его модификациями, дающими результат, похожий на lower_bound и upper_bound — первое и последнее вхождение элемента, либо индекс, куда его можно было бы вставить, если элемент отсутствует

int BinSearchLeft (int numb_to_find, int m[], int start, int end, int middle) {
   end++;
   while (start < end) {
      middle = (start + end) / 2;
      if (m[middle] < numb_to_find) 
          start = middle + 1;
      else
          end = middle;
   return start;
 }

int BinSearchRight (int numb_to_find, int m[], int start, int end, int middle) {
   end++;
   while (start < end) {
      middle = (start + end) / 2;
      if (m[middle] <= numb_to_find) 
          start = middle + 1;
      else
          end = middle;
   return end - 1;
 }

ответ дан 20 окт 2022 в 10:07

MBo's user avatar

MBoMBo

47.8k1 золотой знак17 серебряных знаков40 бронзовых знаков

Введение

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

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

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

В этой статье:

  • Операторы членства (Membership Operators)
  • Линейный поиск
  • Бинарный поиск
  • Улучшенный линейный поиск — Jump Search
  • Поиск Фибоначчи
  • Экспоненциальный поиск
  • Интерполяционный поиск

Операторы членства (Membership Operators)

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

Одной из наиболее распространенных проблем в области компьютерных наук является поиск в коллекции и определение того, присутствует ли данный объект в коллекции или нет.

Почти каждый язык программирования имеет свою собственную реализацию базового алгоритма поиска. Обычно — в виде функции, которая возвращает логическое значение True или False, когда элемент найден в данной коллекции элементов.

В Python самый простой способ поиска объекта — использовать операторы членства. Их название связано с тем, что они позволяют нам определить, является ли данный объект членом коллекции.

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

  • in — возвращает True, если данный элемент присутствует в структуре данных.
  • not in — возвращает True, если данный элемент не присутствует в структуре данных.
>>> 'apple' in ['orange', 'apple', 'grape']
True
>>> 't' in 'pythonist'
True
>>> 'q' in 'pythonist'
False
>>> 'q' not in 'pythonist'
True

Операторов членства достаточно, если нам нужно только определить, существует ли подстрока в данной строке, или пересекаются ли две строки, два списка или кортежа с точки зрения содержащихся  в них объектов.

В большинстве случаев помимо определения, наличествует ли элемент в последовательности, нам нужна еще и позиция (индекс) элемента. Используя операторы членства, мы не можем получить ее.

Существует множество алгоритмов поиска, которые не зависят от встроенных операторов и могут использоваться для более быстрого и/или эффективного поиска значений. Кроме того, они могут дать больше информации (например, о позиции элемента в коллекции), а не просто определить, есть ли в коллекции этот элемент.

Линейный поиск

Линейный поиск — это один из самых простых и понятных алгоритмов поиска. Мы можем думать о нем как о расширенной версии нашей собственной реализации оператора in в Python.

Суть алгоритма заключается в том, чтобы перебрать массив и вернуть индекс первого вхождения элемента, когда он найден:

def LinearSearch(lys, element):
    for i in range (len(lys)):
        if lys[i] == element:
            return i
    return -1

Итак, если мы используем функцию для вычисления:

>>> print(LinearSearch([1,2,3,4,5,2,1], 2))

То получим следующий результат:

1

Это индекс первого вхождения искомого элемента, учитывая, что нумерация элементов в Python начинается с нуля.

Временная сложность линейного поиска равна O(n). Это означает, что время, необходимое для выполнения, увеличивается с увеличением количества элементов в нашем входном списке lys.

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

Линейный поиск хорошо подходит для тех случаев, когда нам нужно найти первое вхождение элемента в несортированной коллекции. Это связано с тем, что он не требует сортировки коллекции перед поиском (в отличие от большинства других алгоритмов поиска).

Бинарный поиск

Бинарный поиск работает по принципу «разделяй и властвуй». Он быстрее, чем линейный поиск, но требует, чтобы массив был отсортирован перед выполнением алгоритма.

Предполагая, что мы ищем значение val в отсортированном массиве, алгоритм сравнивает val со значением среднего элемента массива, который мы будем называть mid.

  • Если mid — это тот элемент, который мы ищем (в лучшем случае), мы возвращаем его индекс.
  • Если нет, мы определяем, в какой половине массива мы будем искать val дальше, основываясь на том, меньше или больше значение val значения mid, и отбрасываем вторую половину массива.
  • Затем мы рекурсивно или итеративно выполняем те же шаги, выбирая новое значение для mid, сравнивая его с val и отбрасывая половину массива на каждой итерации алгоритма.

Алгоритм бинарного поиска можно написать как рекурсивно, так и итеративно. В Python рекурсия обычно медленнее, потому что она требует выделения новых кадров стека.

Поскольку хороший алгоритм поиска должен быть максимально быстрым и точным, давайте рассмотрим итеративную реализацию бинарного поиска:

def BinarySearch(lys, val):
    first = 0
    last = len(lys)-1
    index = -1
    while (first <= last) and (index == -1):
        mid = (first+last)//2
        if lys[mid] == val:
            index = mid
        else:
            if val<lys[mid]:
                last = mid -1
            else:
                first = mid +1
    return index

Если мы используем функцию для вычисления:

>>> BinarySearch([10,20,30,40,50], 20)

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

1

На каждой итерации алгоритм выполняет одно из следующих действий:

  • Возврат индекса текущего элемента.
  • Поиск в левой половине массива.
  • Поиск в правой половине массива.

Мы можем выбрать только одно действие на каждой итерации. Также на каждой итерации наш массив делится на две части. Из-за этого временная сложность двоичного поиска равна O(log n).

Одним из недостатков бинарного поиска является то, что если в массиве имеется несколько вхождений элемента, он возвращает индекс не первого элемента, а  ближайшего к середине:

>>> print(BinarySearch([4,4,4,4,4], 4))

После выполнения этого фрагмента кода будет возвращен индекс среднего элемента:

2

Для сравнения: выполнение линейного поиска по тому же массиву вернет индекс первого элемента:

0

Однако мы не можем категорически утверждать, что двоичный поиск не работает, если массив содержит дубликаты. Он может работать так же, как линейный поиск, и в некоторых случаях возвращать первое вхождение элемента. Например:

>>> print(BinarySearch([1,2,3,4,4,4,5], 4))
3

Бинарный поиск довольно часто используется на практике, потому что он эффективен и быстр по сравнению с линейным поиском. Однако у него есть некоторые недостатки, такие как зависимость от оператора //. Существует много других алгоритмов поиска, работающих по принципу «разделяй и властвуй», которые являются производными от бинарного поиска. Некоторые из них мы рассмотрим далее.

Jump Search

Jump Search похож на бинарный поиск тем, что он также работает с отсортированным массивом и использует аналогичный подход «разделяй и властвуй» для поиска по нему.

Его можно классифицировать как усовершенствованный алгоритм линейного поиска, поскольку он зависит от линейного поиска для выполнения фактического сравнения при поиске значения.

В заданном отсортированном массиве мы ищем не постепенно по элементам массива, а скачкообразно. Если у нас есть размер прыжка, то наш алгоритм будет рассматривать элементы входного списка lys в следующем порядке: lys[0], lys[0+jump], lys[0+2jump], lys[0+3jump] и так далее.

С каждым прыжком мы сохраняем предыдущее значение и его индекс. Когда мы находим множество значений (блок), где lys[i] < element < lys[i + jump], мы выполняем линейный поиск с lys[i] в качестве самого левого элемента и lys[i + jump] в качестве самого правого элемента в нашем множестве:

import math

def JumpSearch (lys, val):
    length = len(lys)
    jump = int(math.sqrt(length))
    left, right = 0, 0
    while left < length and lys[left] <= val:
        right = min(length - 1, left + jump)
        if lys[left] <= val and lys[right] >= val:
            break
        left += jump;
    if left >= length or lys[left] > val:
        return -1
    right = min(length - 1, right)
    i = left
    while i <= right and lys[i] <= val:
        if lys[i] == val:
            return i
        i += 1
    return -1

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

>>> print(JumpSearch([1,2,3,4,5,6,7,8,9], 5))
  • Jump search сначала определит размер прыжка путем вычисления math.sqrt(len(lys)). Поскольку у нас 9 элементов, размер прыжка будет √9 = 3.
  • Далее мы вычисляем значение переменной right. Оно рассчитывается как минимум из двух значений: длины массива минус 1 и значения left + jump, которое в нашем случае будет 0 + 3 = 3. Поскольку 3 меньше 8, мы используем 3 в качестве значения переменной right.
  • Теперь проверим, находится ли наш искомый элемент 5 между lys[0] и lys[3]. Поскольку 5 не находится между 1 и 4, мы идем дальше.
  • Затем мы снова делаем расчеты и проверяем, находится ли наш искомый элемент между lys[3] и lys[6], где 6 — это 3 + jump. Поскольку 5 находится между 4 и 7, мы выполняем линейный поиск по элементам между lys[3] и lys[6] и возвращаем индекс нашего элемента:
4

Временная сложность jump search равна O(√n), где √n — размер прыжка, а n — длина списка. Таким образом, с точки зрения эффективности jump search находится между алгоритмами линейного и бинарного поиска.

Единственное наиболее важное преимущество jump search по сравнению с бинарным поиском заключается в том, что он не опирается на оператор деления (/).

В большинстве процессоров использование оператора деления является дорогостоящим по сравнению с другими основными арифметическими операциями (сложение, вычитание и умножение), поскольку реализация алгоритма деления является итеративной.

Стоимость сама по себе очень мала, но когда количество искомых элементов очень велико, а количество необходимых операций деления растет, стоимость может постепенно увеличиваться. Поэтому jump search лучше бинарного поиска, когда в системе имеется большое количество элементов: там даже небольшое увеличение скорости имеет значение.

Чтобы ускорить jump search, мы могли бы использовать бинарный поиск или какой-нибудь другой алгоритм для поиска в блоке вместо использования гораздо более медленного линейного поиска.

Поиск Фибоначчи

Поиск Фибоначчи — это еще один алгоритм «разделяй и властвуй», который имеет сходство как с бинарным поиском, так и с jump search. Он получил свое название потому, что использует числа Фибоначчи для вычисления размера блока или диапазона поиска на каждом шаге.

Числа Фибоначчи  — это последовательность чисел 0, 1, 1, 2, 3, 5, 8, 13, 21 …, где каждый элемент является суммой двух предыдущих чисел.

Алгоритм работает с тремя числами Фибоначчи одновременно. Давайте назовем эти три числа fibM, fibM_minus_1 и fibM_minus_2. Где fibM_minus_1 и fibM_minus_2 — это два числа, предшествующих fibM в последовательности:

fibM = fibM_minus_1 + fibM_minus_2

Мы инициализируем значения 0, 1, 1 или первые три числа в последовательности Фибоначчи. Это поможет нам избежать  IndexError в случае, когда наш массив lys содержит очень маленькое количество элементов.

Затем мы выбираем наименьшее число последовательности Фибоначчи, которое больше или равно числу элементов в нашем массиве lys, в качестве значения fibM. А два числа Фибоначчи непосредственно перед ним — в качестве значений fibM_minus_1 и fibM_minus_2. Пока в массиве есть элементы и значение fibM больше единицы, мы:

  • Сравниваем val со значением блока в диапазоне до fibM_minus_2 и возвращаем индекс элемента, если он совпадает.
  • Если значение больше, чем элемент, который мы в данный момент просматриваем, мы перемещаем значения fibM, fibM_minus_1 и fibM_minus_2 на два шага вниз в последовательности Фибоначчи и меняем индекс на индекс элемента.
  • Если значение меньше, чем элемент, который мы в данный момент просматриваем, мы перемещаем значения fibM, fibM_minus_1 и fibM_minus_2 на один шаг вниз в последовательности Фибоначчи.

Давайте посмотрим на реализацию этого алгоритма на Python:

def FibonacciSearch(lys, val):
    fibM_minus_2 = 0
    fibM_minus_1 = 1
    fibM = fibM_minus_1 + fibM_minus_2
    while (fibM < len(lys)):
        fibM_minus_2 = fibM_minus_1
        fibM_minus_1 = fibM
        fibM = fibM_minus_1 + fibM_minus_2
    index = -1;
    while (fibM > 1):
        i = min(index + fibM_minus_2, (len(lys)-1))
        if (lys[i] < val):
            fibM = fibM_minus_1
            fibM_minus_1 = fibM_minus_2
            fibM_minus_2 = fibM - fibM_minus_1
            index = i
        elif (lys[i] > val):
            fibM = fibM_minus_2
            fibM_minus_1 = fibM_minus_1 - fibM_minus_2
            fibM_minus_2 = fibM - fibM_minus_1
        else :
            return i
    if(fibM_minus_1 and index < (len(lys)-1) and lys[index+1] == val):
        return index+1;
    return -1

Используем функцию FibonacciSearch для вычисления:

>>> print(FibonacciSearch([1,2,3,4,5,6,7,8,9,10,11], 6))

Давайте посмотрим на пошаговый процесс поиска:

  • Присваиваем переменной fibM наименьшее число Фибоначчи, которое больше или равно длине списка. В данном случае наименьшее число Фибоначчи, отвечающее нашим требованиям, равно 13.
  • Значения присваиваются следующим образом:

           fibM = 13

           fibM_minus_1 = 8

           fibM_minus_2 = 5

           index = -1

  • Далее мы проверяем элемент lys[4], где 4 — это минимум из двух значений — index + fibM_minus_2 (-1+5) и длина массива минус 1 (11-1). Поскольку значение lys[4] равно 5, что меньше искомого значения, мы перемещаем числа Фибоначчи на один шаг вниз в последовательности, получая следующие значения:

           fibM = 8

           fibM_minus_1 = 5

           fibM_minus_2 = 3

           index = 4

  • Далее мы проверяем элемент lys[7], где 7 — это минимум из двух значений: index + fibM_minus_2 (4 + 3) и длина массива минус 1 (11-1). Поскольку значение lys[7] равно 8, что больше искомого значения, мы перемещаем числа Фибоначчи на два шага вниз в последовательности, получая следующие значения: 

           fibM = 3

           fibM_minus_1 = 2

           fibM_minus_2 = 1

           index = 4

  • Затем мы проверяем элемент lys[5], где 5 — это минимум из двух значений: index + fibM_minus_2 (4+1) и длина массива минус 1 (11-1) . Значение lys[5] равно 6, и это наше искомое значение!

Получаем ожидаемый результат:

5

Временная сложность поиска Фибоначчи равна O(log n). Она такая же, как и у бинарного поиска. Это означает, что алгоритм в большинстве случаев работает быстрее, чем линейный поиск и jump search.

Поиск Фибоначчи можно использовать, когда у нас очень большое количество искомых элементов и мы хотим уменьшить неэффективность, связанную с использованием алгоритма, основанного на операторе деления.

Дополнительным преимуществом использования поиска Фибоначчи является то, что он может вместить входные массивы, которые слишком велики для хранения в кэше процессора или ОЗУ, потому что он ищет элементы с увеличивающимся шагом, а не с фиксированным.

Экспоненциальный поиск

Экспоненциальный поиск — это еще один алгоритм поиска, который может быть достаточно легко реализован на Python, по сравнению с jump search и поиском Фибоначчи, которые немного сложны. Он также известен под названиями galloping search, doubling search и Struzik search.

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

  1. Определяется диапазон, в котором, скорее всего, будет находиться искомый элемент.
  2. В этом диапазоне используется двоичный поиск для нахождения индекса элемента.

Реализация алгоритма экспоненциального поиска на Python:

def ExponentialSearch(lys, val):
    if lys[0] == val:
        return 0
    index = 1
    while index < len(lys) and lys[index] <= val:
        index = index * 2
    return BinarySearch( lys[:min(index, len(lys))], val)

Используем функцию, чтобы найти значение:

>>> print(ExponentialSearch([1,2,3,4,5,6,7,8],3))

Рассмотрим работу алгоритма пошагово.

  • Проверяем, соответствует ли первый элемент списка искомому значению: поскольку lys[0] равен 1, а мы ищем 3, мы устанавливаем индекс равным 1 и двигаемся дальше.
  • Перебираем все элементы в списке, и пока элемент с текущим индексом меньше или равен нашему значению, умножаем  значение индекса на 2:
  1. index = 1, lys[1] равно 2, что меньше 3, поэтому значение index умножается на 2 и переменной index присваивается значение 2.
  2. index = 2, lys[2] равно 3, что равно 3, поэтому значение index умножается на 2 и переменной index присваивается значение 4.
  3. index = 4, lys[4] равно 5, что больше 3. Условие выполнения цикла больше не соблюдается и цикл завершает свою работу.
  • Затем выполняется двоичный поиск в полученном диапазоне (срезе) lys[:4]. В Python это означает, что подсписок будет содержать все элементы до 4-го элемента, поэтому мы фактически вызываем функцию следующим образом:
>>> BinarySearch([1,2,3,4], 3)

Функция вернет следующий результат:

2

Этот результат является индексом искомого элемента как в исходном списке, так и в срезе, который мы передаем алгоритму бинарного поиска.

Экспоненциальный поиск выполняется за время O(log i), где i — индекс искомого элемента. В худшем случае временная сложность равна O(log n), когда искомый элемент — это последний элемент в массиве (n — это длина массива).

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

Интерполяционный поиск

Интерполяционный поиск — это еще один алгоритм «разделяй и властвуй», аналогичный бинарному поиску. В отличие от бинарного поиска, он не всегда начинает поиск с середины. Интерполяционный поиск вычисляет вероятную позицию искомого элемента по формуле:

index = low + [(val-lys[low])*(high-low) / (lys[high]-lys[low])]

В этой формуле используются следующие переменные:

  • lys — наш входной массив.
  • val — искомый элемент.
  • index — вероятный индекс искомого элемента. Он вычисляется как более высокое значение, когда значение val ближе по значению к элементу в конце массива (lys[high]), и более низкое, когда значение val ближе по значению к элементу в начале массива (lys[low]).
  • low — начальный индекс массива.
  • high — последний индекс массива.

Алгоритм осуществляет поиск путем вычисления значения индекса:

  • Если значение найдено (когда lys[index] == val), возвращается индекс.
  • Если значение val меньше lys[index], то значение индекса пересчитывается по формуле для левого подмассива.
  • Если значение val больше lys[index], то значение индекса пересчитывается по формуле для правого подмассива.

Давайте  посмотрим на реализацию интерполяционного поиска на Python:

def InterpolationSearch(lys, val):
    low = 0
    high = (len(lys) - 1)
    while low <= high and val >= lys[low] and val <= lys[high]:
        index = low + int(((float(high - low) / ( lys[high] - lys[low])) * ( val - lys[low])))
        if lys[index] == val:
            return index
        if lys[index] < val:
            low = index + 1;
        else:
            high = index - 1;
    return -1

Если мы используем функцию для вычисления:

>>> print(InterpolationSearch([1,2,3,4,5,6,7,8], 6))

Наши начальные значения будут следующими:

val = 6,

low = 0,

high = 7,

lys[low] = 1,

lys[high] = 8,

index = 0 + [(6-1)*(7-0)/(8-1)] = 5

Поскольку lys[5] равно 6, что является искомым значением, мы прекращаем выполнение и возвращаем результат:

5

Если у нас большое количество элементов и наш индекс не может быть вычислен за одну итерацию, то мы продолжаем пересчитывать значение индекса после корректировки значений high и low.

Временная сложность интерполяционного поиска равна O(log log n), когда значения распределены равномерно. Если значения распределены неравномерно, временная сложность для наихудшего случая равна O(n) — так же, как и для линейного поиска.

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

Python очень удобочитаемый и эффективный по сравнению с такими языками программирования, как Java, Fortran, C, C++ и т. д. Одним из ключевых преимуществ использования Python для реализации алгоритмов поиска является то, что вам не нужно беспокоиться о приведении или явной типизации.

В Python большинство алгоритмов поиска, которые мы обсуждали, будут работать так же хорошо, если мы ищем строку. Имейте в виду, что понадобится внести изменения в код для алгоритмов, которые используют искомый элемент для числовых вычислений, например алгоритм интерполяционного поиска.

Python также подходит, если вы хотите сравнить производительность различных алгоритмов поиска для вашего dataset’а. Создание прототипа на Python проще и быстрее, потому что вы можете сделать больше с меньшим количеством строк кода.

Чтобы сравнить производительность наших реализованных алгоритмов, в Python мы можем использовать библиотеку time:

import time

start = time.time()
# вызовите здесь функцию
end = time.time()
print(start-end)

Заключение

Существует множество возможных способов поиска элемента в коллекции. В этой статье мы обсудили несколько алгоритмов поиска и их реализации на Python.

Выбор используемого алгоритма зависит от данных, с которыми вы будете работать. Это ваш входной массив, который мы называли lys во всех наших реализациях.

  • Если вы хотите выполнить поиск в несортированном массиве или найти первое вхождение искомой переменной, то лучшим вариантом будет линейный поиск.
  • Если вы хотите выполнить поиск в отсортированном массиве, есть много вариантов, из которых самый простой и быстрый — это бинарный поиск.
  • Если у вас есть отсортированный массив, в котором вы хотите выполнить поиск без использования оператора деления, вы можете использовать либо jump search, либо поиск Фибоначчи.
  • Если вы знаете, что искомый элемент, скорее всего, находится ближе к началу массива, вы можете использовать экспоненциальный поиск.
  • Если ваш отсортированный массив равномерно распределен, то самым быстрым и эффективным будет интерполяционный поиск.

Если вы не уверены, какой алгоритм использовать для отсортированного массива, просто протестируйте каждый из них при помощи библиотеки time и выберите тот, который лучше всего работает с вашим dataset’ом.

(PHP 4 >= 4.0.5, PHP 5, PHP 7, PHP 8)

array_searchОсуществляет поиск данного значения в массиве и возвращает
ключ первого найденного элемента в случае успешного выполнения

Описание

array_search(mixed $needle, array $haystack, bool $strict = false): int|string|false

Список параметров

needle

Искомое значение.

Замечание:

Если needle является строкой, сравнение
происходит с учётом регистра.

haystack

Массив.

strict

Если третий параметр strict установлен в
true, то функция array_search() будет искать
идентичные элементы в haystack.
Это означает, что также будут проверяться
типы
needle в haystack,
а объекты должны быть одним и тем же экземпляром.

Возвращаемые значения

Возвращает ключ для needle, если он был
найден в массиве, иначе false.

Если needle присутствует в
haystack более одного раза, будет возвращён
первый найденный ключ. Для того, чтобы возвратить ключи для всех
найденных значений, используйте функцию array_keys()
с необязательным параметром search_value.

Внимание

Эта функция может возвращать как логическое значение false, так и значение не типа boolean, которое приводится к false. За более подробной информацией обратитесь к разделу Булев тип. Используйте оператор === для проверки значения, возвращаемого этой функцией.

Примеры

Пример #1 Пример использования array_search()


<?php
$array
= array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red');$key = array_search('green', $array); // $key = 2;
$key = array_search('red', $array); // $key = 1;
?>

Смотрите также

  • array_keys() — Возвращает все или некоторое подмножество ключей массива
  • array_values() — Выбирает все значения массива
  • array_key_exists() — Проверяет, присутствует ли в массиве указанный ключ или индекс
  • in_array() — Проверяет, присутствует ли в массиве значение

turabgarip at gmail dot com

6 years ago


About searcing in multi-dimentional arrays; two notes on "xfoxawy at gmail dot com";

It perfectly searches through multi-dimentional arrays combined with array_column() (min php 5.5.0) but it may not return the values you'd expect.

<?php array_search($needle, array_column($array, 'key')); ?>

Since array_column() will produce a resulting array; it won't preserve your multi-dimentional array's keys. So if you check against your keys, it will fail.

For example;

<?php
$people
= array(
 
2 => array(
   
'name' => 'John',
   
'fav_color' => 'green'
 
),
 
5=> array(
   
'name' => 'Samuel',
   
'fav_color' => 'blue'
 
)
);
$found_key = array_search('blue', array_column($people, 'fav_color'));
?>

Here, you could expect that the $found_key would be "5" but it's NOT. It will be 1. Since it's the second element of the produced array by the array_column() function.

Secondly, if your array is big, I would recommend you to first assign a new variable so that it wouldn't call array_column() for each element it searches. For a better performance, you could do;

<?php
$colors
= array_column($people, 'fav_color');
$found_key = array_search('blue', $colors);
?>


cue at openxbox dot com

19 years ago


If you are using the result of array_search in a condition statement, make sure you use the === operator instead of == to test whether or not it found a match.  Otherwise, searching through an array with numeric indicies will result in index 0 always getting evaluated as false/null.  This nuance cost me a lot of time and sanity, so I hope this helps someone.  In case you don't know what I'm talking about, here's an example:

<?php

$code
= array("a", "b", "a", "c", "a", "b", "b"); // infamous abacabb mortal kombat code :-P

// this is WRONG

while (($key = array_search("a", $code)) != NULL)

{

// infinite loop, regardless of the unset

unset($code[$key]);

}
// this is _RIGHT_

while (($key = array_search("a", $code)) !== NULL)

{

// loop will terminate

unset($code[$key]);

}

?>


stefano@takys dot it

12 years ago


for searching case insensitive better this:

<?php

array_search
(strtolower($element),array_map('strtolower',$array));

?>


RichGC

17 years ago


To expand on previous comments, here are some examples of
where using array_search within an IF statement can go
wrong when you want to use the array key thats returned.

Take the following two arrays you wish to search:

<?php
$fruit_array
= array("apple", "pear", "orange");
$fruit_array = array("a" => "apple", "b" => "pear", "c" => "orange");

if (

$i = array_search("apple", $fruit_array))
//PROBLEM: the first array returns a key of 0 and IF treats it as FALSEif (is_numeric($i = array_search("apple", $fruit_array)))
//PROBLEM: works on numeric keys of the first array but fails on the secondif ($i = is_numeric(array_search("apple", $fruit_array)))
//PROBLEM: using the above in the wrong order causes $i to always equal 1if ($i = array_search("apple", $fruit_array) !== FALSE)
//PROBLEM: explicit with no extra brackets causes $i to always equal 1if (($i = array_search("apple", $fruit_array)) !== FALSE)
//YES: works on both arrays returning their keys
?>


thinbegin at gmail dot com

5 years ago


Despite PHP's amazing assortment of array functions and juggling maneuvers, I found myself needing a way to get the FULL array key mapping to a specific value. This function does that, and returns an array of the appropriate keys to get to said (first) value occurrence.

function array_recursive_search_key_map($needle, $haystack) {
    foreach($haystack as $first_level_key=>$value) {
        if ($needle === $value) {
            return array($first_level_key);
        } elseif (is_array($value)) {
            $callback = array_recursive_search_key_map($needle, $value);
            if ($callback) {
                return array_merge(array($first_level_key), $callback);
            }
        }
    }
    return false;
}

usage example:
-------------------

$nested_array = $sample_array = array(
    'a' => array(
        'one' => array ('aaa' => 'apple', 'bbb' => 'berry', 'ccc' => 'cantalope'),
        'two' => array ('ddd' => 'dog', 'eee' => 'elephant', 'fff' => 'fox')
    ),
    'b' => array(
        'three' => array ('ggg' => 'glad', 'hhh' => 'happy', 'iii' => 'insane'),
        'four' => array ('jjj' => 'jim', 'kkk' => 'kim', 'lll' => 'liam')
    ),
    'c' => array(
        'five' => array ('mmm' => 'mow', 'nnn' => 'no', 'ooo' => 'ohh'),
        'six' => array ('ppp' => 'pidgeon', 'qqq' => 'quail', 'rrr' => 'rooster')
    )
);

$search_value = 'insane';

$array_keymap = array_recursive_search_key_map($search_value, $nested_array);

var_dump($array_keymap);
// Outputs:
// array(3) {
// [0]=>
//  string(1) "b"
//  [1]=>
//  string(5) "three"
//  [2]=>
//  string(3) "iii"
//}

----------------------------------------------

But again, with the above solution, PHP again falls short on how to dynamically access a specific element's value within the nested array. For that, I wrote a 2nd function to pull the value that was mapped above.

function array_get_nested_value($keymap, $array)
{
    $nest_depth = sizeof($keymap);
    $value = $array;
    for ($i = 0; $i < $nest_depth; $i++) {
        $value = $value[$keymap[$i]];
    }

    return $value;
}

usage example:
-------------------
echo array_get_nested_value($array_keymap, $nested_array);   // insane


opencart dot ocfilter at gmail dot com

1 year ago


Be careful!

<?php

var_dump

(array_search('needle', [ 0 => 0 ])); // int(0) (!)var_dump(array_search('needle', [ 0 => 0 ], true)); // bool(false)?>

But, in php 8

<?php

var_dump

(array_search('needle', [ 0 => 0 ])); // bool(false)?>


maciej at speccode dot com

7 years ago


FYI, remember that strict mode is something that might save you hours.

If you're searching for a string and you have a "true" boolean on the way - you will get it as result (first occurrence). Example below:

<?php

$arr

= [
   
'foo'    => 'bar',
   
'abc'    => 'def',
   
'bool'   => true,
   
'target' => 'xyz'
];var_dump( array_search( 'xyz', $arr ) ); //bool
var_dump( array_search( 'xyz', $arr, true ) ); //target?>


azaozz, gmail

14 years ago


Expanding on the comment by hansen{}cointel.de:

When searching for a string and the array contains 0 (zero), the string is casted to (int) by the type-casting which is always 0 (perhaps the opposite is the proper behaviour, the array value 0 should have been casted to string). That produces unexpected results if strict comparison is not used:

<?php
$a
= array(0, "str1", "str2", "str3");
echo
"
str1 = "
.array_search("str1", $a).",
str2 = "
.array_search("str2", $a).",
str3 = "
.array_search("str3", $a).",

str1 strict = "

.array_search("str1", $a, true).",
str2 strict = "
.array_search("str2", $a, true).",
str3 strict = "
.array_search("str3", $a, true);
?>

This will return:
str1 = 0, str2 = 0, str3 = 0, str1 strict = 1, str2 strict = 2, str3 strict = 3


codeslinger at compsalot dot com

13 years ago


one thing to be very aware of is that array_search() will fail if the needle is a string and the array itself contains values that are mixture of numbers and strings.  (or even a string that looks like a number)

The problem is that unless you specify "strict" the match is done using ==    and in that case any string will match a numeric value of zero which is not what you want.

-----

also, php can lookup an index pretty darn fast.  for many scenarios, it is practical to maintain multiple arrays, one in which the index of the array is the search key and the normal array that contains the data.

<?php

  $normal

[$index] = array('key'=>$key, 'data'=>'foo');

 
$inverse[$key] = $index;
//very fast lookup, this beats any other kind of search
if (array_key_exists($key, $inverse))

  {

   
$index = $inverse[$key];

    return
$normal[$index];

  }
?>


n-regen

14 years ago


If you only know a part of a value in an array and want to know the complete value, you can use the following function:
<?php
function array_find($needle, $haystack)
{
   foreach (
$haystack as $item)
   {
      if (
strpos($item, $needle) !== FALSE)
      {
         return
$item;
         break;
      }
   }
}
?>
The function returns the complete first value of $haystack that contains $needle.

andreas dot damm at maxmachine dot de

15 years ago


Combining syntax of array_search() and functionality of array_keys() to get all key=>value associations of an array with the given search-value:
<?php
function array_search_values( $m_needle, $a_haystack, $b_strict = false){
    return
array_intersect_key( $a_haystack, array_flip( array_keys( $a_haystack, $m_needle, $b_strict)));
}
?>

Usage:
<?php
$array1
= array( 'pre'=>'2', 1, 2, 3, '1', '2', '3', 'post'=>2);
print_r( array_search_values( '2', $array1));
print_r( array_search_values( '2', $array1, true));
print_r( array_search_values( 2, $array1, true));
?>

Will return:
array(4) {
    ["pre"] =>
    string(1) "2"
    [1] =>
    int(2)
    [4] =>
    string(1) "2"
    ["post"] =>
    int(2)
}
array(2) {
    ["pre"] =>
    string(1) "2"
    [4] =>
    string(1) "2"
}
array(2) {
    [1] =>
    int(2)
    ["post"] =>
    int(2)
}

yasien dot dwieb at gmail dot com

3 years ago


Beware when using array_search to a mix of string and integer where prefixes of keys may collide, as in my case I have encountered the following situation:

Assume you have the following array:
<?php
$arr
= [
          
1 => 'index 0',
          
2 => 'index 1',
          
3 => 'index 2',
          
'3anothersuffix' => 'index 3'
];$index1 = array_search('3', array_keys($arr)); // 2
$index2 = array_search('3anothersuffix', array_keys($arr)); //2
?>

$index1 and $index2 will be the same

after using strict type search:

<?php
$index1
= array_search('3', array_keys($arr), true); // false
$index2 = array_search('3anothersuffix', array_keys($arr), true);  //3
?>

it will not find $index1 at all while returning a correct value for $index2;


stooshie at gmail dot com

11 years ago


Example of a recursive binary search that returns the index rather than boolean.
<?php
// returns the index of needle in haystack
function binSearch($needle, $haystack)
{
   
// n is only needed if counting depth of search
   
global $n;
   
$n++;
   
// get the length of passed array
   
$l = count($haystack);
   
// if length is 0, problem
   
if($l <= 0)
    {
        return -
1;
    }
   
// get the mid element
   
$m = (($l+($l%2))/2);
   
// if mid >= length (e.g. l=1)
   
if($m >= $l)
    {
       
$m = $m-1;
    }
   
// get the indexed element to compare to the passed element and branch accordingly
   
$compare = $haystack[$m];
    switch(
true)
    {
        case(
$compare>$needle):
        {
           
// recurse on the lower half
           
$new_haystack = array_slice($haystack, 0, $m);
           
$c = count($new_haystack);
           
$r = binSearch($needle, $new_haystack);
           
// return current index - (length of lower half - found index in lower half)
           
return $m - ($c - $r);
            break;
        }
        case(
$compare<$needle):
        {
           
// recurse on the upper half
           
$new_haystack = array_slice($haystack, $m, ($l-$m));
           
$c = count($new_haystack);
           
$r = binSearch($needle, $new_haystack);
           
// return current position + found index in upper half
           
return $m + $r;
            break;
        }
        case(
$compare==$needle):
        {
           
// found it, so return index
           
return $m;
            break;
        }
    }
}
?>

helenadeus at gmail dot com

14 years ago


I was trying to use array_search to retrieve all the values that match a given needle, but it turns out only the first match key is returned. I built this little function, which works just like array_search, but returns all the keys that match a given needle instead. The output is an array.

<?php

$haystack

= array('a','b','a','b');$needle = 'a';print_r(array_search_all($needle, $haystack));//Output will be
// Array
// (
//         [0]=>1
//         [1]=>3
// )
function array_search_all($needle, $haystack)
{
#array_search_match($needle, $haystack) returns all the keys of the values that match $needle in $haystackforeach ($haystack as $k=>$v) {

            if(

$haystack[$k]==$needle){$array[] = $k;
        }
    }
    return (
$array);

    }

?>


nordseebaer at gmx dot de

3 years ago


It's really important to check the return value is not false! I used array_search() to determine the index of an value to unset this value and then realized that $arr[false] === $arr[0] !

<?php
$arr
= ['apple', 'banana'];var_dump($arr[0] === 'apple'); // true
var_dump($arr[false] === $arr[0]); // true
var_dump($arr[false] === 'apple'); // trueunset($arr[array_search('banana', $arr)]); //index = 1
var_dump($arr);// result
//   array(1) {
//     [0]=>
//     string(5) "apple"
//   }
unset($arr[array_search('peach', $arr)]); //not found, result is false
var_dump($arr);// result
//   array(0) {
//   }
// because $arr[false] === $arr[0]
?>

So always check the return of array_search!


kermes [at] thesevens [dot] net

15 years ago


A variation of previous searches that returns an array of keys that match the given value:

<?php
function array_ksearch($array, $str)
{
   
$result = array();
    for(
$i = 0; $i < count($array); next($array), $i++)
        if(
strtolower(current($array)) == strtolower($str))
           
array_push($result, key($array);

        return

$result;
}
?>

Usage would be as follows:
<?php
$testArray
= array('one' => 'test1', 'two' => 'test2', 'three' => 'test1', 'four' => 'test2', 'five' => 'test1');
   
print_r(array_ksearch($testArray, 'test1'));
?>


Понравилась статья? Поделить с друзьями:
  • Как найти капитал по вкладам
  • Украли телефон как найти телефон по интернету
  • Как найти карту личности
  • Как исправить ошибку на компьютере 0xc000000d
  • Как найти на reddit