Подтвердить что ты не робот

Найти повторяющиеся элементы в массиве с помощью Swift

Как найти повторяющиеся элементы в массиве? У меня есть массив телефонных номеров, поэтому в телефонных номерах я должен начать поиск с правой стороны влево и найти похожие 6 целых чисел. то я должен распечатать их.

4b9b3361

Ответ 1

Чтобы найти дубликаты, вы можете создать перекрестную ссылку по номеру телефона, а затем фильтровать только до дубликатов. Например, рассмотрим:

let contacts = [
    Contact(name: "Rob",     phone: "555-1111"),
    Contact(name: "Richard", phone: "555-2222"),
    Contact(name: "Rachel",  phone: "555-1111"),
    Contact(name: "Loren",   phone: "555-2222"),
    Contact(name: "Mary",    phone: "555-3333"),
    Contact(name: "Susie",   phone: "555-2222")
]

В Swift 4 вы можете создать словарь перекрестных ссылок с помощью:

let crossReference = Dictionary(grouping: contacts, by: { $0.phone })

или

let crossReference = contacts.reduce(into: [String: [Contact]]()) {
    $0[$1.phone, default: []].append($1)
}

Затем, чтобы найти дубликаты:

let duplicates = crossReference
    .filter { $1.count > 1 }                 // filter down to only those with multiple contacts
    .sorted { $0.1.count > $1.1.count }      // if you want, sort in descending order by number of duplicates

Очевидно, что использование любых типов моделей имеет смысл для вас, но в приведенном выше примере используется следующий тип Contact:

struct Contact {
    let name: String
    let phone: String
}

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


Похоже, вы хотите сгладить эту структуру, которая отражает дубликаты, в один массив контактов (я не уверен, почему вы хотите это сделать, поскольку вы теряете структуру, идентифицирующую, которые являются дубликатами друг друга), но если вы хотите это сделать, вы можете flatMap его:

let flattenedDuplicates = crossReference
    .filter { $1.count > 1 }                 // filter down to only those with multiple contacts
    .flatMap { $0.1 }                        // flatten it down to just array of contacts that are duplicates of something else

Для строк Swift 2 или 3 см. предыдущие версии этого ответа.

Ответ 2

Чувство ~ умное ~. Для массива Int s

let x = [1, 1, 2, 3, 4, 5, 5]
let duplicates = Array(Set(x.filter({ (i: Int) in x.filter({ $0 == i }).count > 1})))
// [1, 5]

Обратите внимание, что это ужасно эффективно для всех участников, включая компилятор и вас.

Я просто хвастаюсь.

Ответ 3

Чтобы фильтровать массив на основе свойств, вы можете использовать этот метод:

extension Array {

    func filterDuplicates(@noescape includeElement: (lhs:Element, rhs:Element) -> Bool) -> [Element]{
        var results = [Element]()

        forEach { (element) in
            let existingElements = results.filter {
                return includeElement(lhs: element, rhs: $0)
            }
            if existingElements.count == 0 {
                results.append(element)
            }
        }

        return results
    }
}

Что вы можете назвать следующим, на основе примера контактов Rob:

let filteredContacts = myContacts.filterDuplicates { $0.name == $1.name && $0.phone == $1.phone }

Ответ 4

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

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

var phoneNumbers = [123456, 234567, 345678, 123456, 456789, 135790, 456789, 142638]

func findDuplicates(sortedArray array: [Int]) -> [Int]
{
    var duplicates: [Int] = []

    var prevItem: Int = 0
    var addedItem: Int = 0

    for item in array
    {
        if(prevItem == item && addedItem != item)
        {
            duplicates.append(item)
            addedItem = item
        }

        prevItem = item
    }

    return duplicates
}

func sortPhoneNumbers(phoneNumbers: [Int]) -> [Int]
{
    return phoneNumbers.sorted({ return $0<$1 })
}

sortPhoneNumbers(phoneNumbers)
findDuplicates(sortPhoneNumbers(phoneNumbers))

Кроме того, вы можете реализовать метод findDuplicates по-разному:

Использование Set (Swift 1.2 +):

func findDuplicates(array: [Int]) -> [Int]
{
    var duplicates = Set<Int>()
    var prevItem = 0       

    for item in array
    {
        if(prevItem == item)
        {
            duplicates.insert(item)
        }

        prevItem = item
    }

    return Array(duplicates)
}

И так далее.

Ответ 5

То же, что и в @tikhop, но как расширение массива (Swift 3):

extension Array where Element: Comparable & Hashable {

   public var duplicates: [Element] {

      let sortedElements = sorted { $0 < $1 }
      var duplicatedElements = Set<Element>()

      var previousElement: Element?
      for element in sortedElements {
         if previousElement == element {
            duplicatedElements.insert(element)
         }
         previousElement = element
      }

      return Array(duplicatedElements)
   }

}

Ответ 6

Очень простой ответ, который сохраняет все дубликаты

let originalNums = [5, 3, 2, 3 , 7 , 5,3]
var nums = Array(originalNums)

let numSet = Set(nums)

for num in numSet {
  if let index = nums.index(of: num) {
     nums.remove(at: index)
  }
}

Выход

[3, 5, 3]

Ответ 7

Я нашел способ, используя сокращение, вот код (Swift 4):

let testNumbers = [1,1,2,3,4,5,2]
let nondupicate = testNumbers.reduce(into: [Int]()) {
    if !$0.contains($1) {
        $0.append($1)
    } else {
        print("Found dupicate: \($1)")
    }
}

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

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

Ответ 8

У меня также была аналогичная проблема и преодолели следующим образом. (Xcode 8.3.2)

let a = [123456, 234567, 345678, 123456, 456789, 135790, 456789, 142638]
var b = a // copy-on-write so that "a" won't be modified

while let c = b.popLast() {
  b.forEach() {
    if $0 == c {
      Swift.print("Duplication: \(c)")
    }
  }
}

//  Duplication: 456789
//  Duplication: 123456

Дело в том, что количество сравнений. Он будет меньше других.

Предположим, что количество элементов в массиве равно N. В каждом цикле число будет уменьшаться на единицу. Таким образом, общее число будет (N-1) + (N-2) + (N-3) +... + 2 + 1 = N * (N-1)/2 Когда N = 10, это будет 9 + 8 +... = 45

В отличие от некоторых алгоритмов может быть N * N. Когда N = 10, что будет 100.

Несмотря на это, принимая во внимание стоимость глубокой копии или мелкой копии, я согласен с тем, что @Patrick Perini блестящий путь был бы лучше, чем в некоторых ситуациях, даже число из них было бы N * N.

EDIT:

Альтернативный способ с IteratorProtocol

let a = [123456, 234567, 345678, 123456, 456789, 135790, 456789, 142638]
var i = a.makeIterator()

while let c = i.next() {
  var j = i
  while let d = j.next() {
    if c == d {
      Swift.print("Duplication: \(c)")
    }
  }
}

//  Duplication: 123456
//  Duplication: 456789

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

Моя забота - это эффективность, то есть более быстрая реакция на интерфейс, более длительный срок службы батареи, меньшая занимаемая площадь памяти и т.д. Избегание ненужных распределений памяти и/или копий памяти, которые автоматически выполняются Swift в скрытой сцене, будет иметь решающее значение, если мы обеспечим конкурентоспособность продукты. (-;

Ответ 9

Antoine solution в синтаксисе Swift 3 +

extension Array {

    func filterDuplicates(includeElement: @escaping (_ lhs: Element, _ rhs: Element) -> Bool) -> [Element] {

        var results = [Element]()

        forEach { (element) in

            let existingElements = results.filter {
                return includeElement(element, $0)
            }

            if existingElements.count == 0 {
                results.append(element)
            }
        }
        return results
    }
}