Jak łączyć lub scalać tablice w Swift?


Odpowiedzi:


691

Możesz łączyć tablice +, budując nową tablicę

let c = a + b
print(c) // [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]

lub dołącz jedną tablicę do drugiej za pomocą +=(lub append):

a += b

// Or:
a.append(contentsOf: b)  // Swift 3
a.appendContentsOf(b)    // Swift 2
a.extend(b)              // Swift 1.2

print(a) // [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]

[AnyObect]? nie jest identyczny z CGFloat. Podczas łączenia z tablicami AnyObject.
khunshan

6
Khunshan: AnyObjectwskazuje obiekt, który, jak rozumiem, oznacza coś, co jest tworzone z typu klasy. CGFloatnie jest przedmiotem, to wartość skalarna. Jak rozumiem, tablice mogą zawierać skalary, chyba że są zdefiniowane jako zawierające AnyObjectlub są dalej ulepszane. Jednak podejrzewam tu problemem jest to, że tablica jest owinięty w opcjonalny, więc trzeba rozpakować go !lub ?pierwszy.
Owen Godfrey

Czy wiemy, czy inteligencja Swift 2 Copy-On-Write rozciąga się na ustalenie, czy bczęść ajest modyfikowana (a zatem może pomijać kopię bpodczas a.appendContentsOf(b))?
Efemeryda

1
@OwenGodfrey dzięki. mam mylące zdanie na temat appendContentsOf i insertContentsOf.
khunshan


137

W Swift 5, zgodnie z własnymi potrzebami, możesz wybrać jeden z sześciu poniższych sposobów łączenia / łączenia dwóch tablic.


# 1. Łączy dwie matryce do nowej tablicy z Array„s +(_:_:)operatora rodzajowego

Arrayma +(_:_:)ogólny operator. +(_:_:)ma następującą deklarację :

Tworzy nową kolekcję, łącząc elementy kolekcji i sekwencji.

static func + <Other>(lhs: Array<Element>, rhs: Other) -> Array<Element> where Other : Sequence, Self.Element == Other.Element

Poniższy przykładowy kod Playground pokazuje, jak połączyć dwie tablice typu [Int]w nową tablicę za pomocą +(_:_:)operatora ogólnego:

let array1 = [1, 2, 3]
let array2 = [4, 5, 6]

let flattenArray = array1 + array2
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]

# 2. Dołączyć elementy tablicy w istniejącej matrycy z Array„S +=(_:_:)operatora rodzajowego

Arrayma +=(_:_:)ogólny operator. +=(_:_:)ma następującą deklarację :

Dołącza elementy sekwencji do kolekcji wymiennej w zakresie.

static func += <Other>(lhs: inout Array<Element>, rhs: Other) where Other : Sequence, Self.Element == Other.Element

Poniższy przykładowy kod Playground pokazuje, jak dołączyć elementy tablicy typu [Int]do istniejącej tablicy za pomocą +=(_:_:)operatora ogólnego:

var array1 = [1, 2, 3]
let array2 = [4, 5, 6]

array1 += array2
print(array1) // prints [1, 2, 3, 4, 5, 6]

# 3. Dołączania matrycy na drugiej tablicy o Array„s append(contentsOf:)metody

Swift Arrayma append(contentsOf:)metodę. append(contentsOf:)ma następującą deklarację :

Dodaje elementy sekwencji lub kolekcji na końcu tej kolekcji.

mutating func append<S>(contentsOf newElements: S) where S : Sequence, Self.Element == S.Element

Poniższy przykładowy kod Playground pokazuje, jak dołączyć tablicę do innej tablicy typu [Int]za pomocą append(contentsOf:)metody:

var array1 = [1, 2, 3]
let array2 = [4, 5, 6]

array1.append(contentsOf: array2)
print(array1) // prints [1, 2, 3, 4, 5, 6]

# 4. Łączy dwie matryce do nowej tablicy z Sequence„s flatMap(_:)metody

Swift zapewnia flatMap(_:)metodę dla wszystkich typów zgodnych z Sequenceprotokołem (w tym Array). flatMap(_:)ma następującą deklarację :

Zwraca tablicę zawierającą połączone wyniki wywołania danej transformacji z każdym elementem tej sekwencji.

func flatMap<SegmentOfResult>(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence

Poniższy przykładowy kod Playground pokazuje, jak połączyć dwie tablice typu [Int]w nową tablicę przy użyciu flatMap(_:)metody:

let array1 = [1, 2, 3]
let array2 = [4, 5, 6]

let flattenArray = [array1, array2].flatMap({ (element: [Int]) -> [Int] in
    return element
})
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]

# 5. Łączy dwie matryce do nowej tablicy z Sequence's joined()sposobem i Arrayjest init(_:)inicjator

Swift zapewnia joined()metodę dla wszystkich typów zgodnych z Sequenceprotokołem (w tym Array). joined()ma następującą deklarację :

Zwraca elementy tej sekwencji sekwencji, połączone.

func joined() -> FlattenSequence<Self>

Poza tym Swift Arrayma init(_:)inicjalizator. init(_:)ma następującą deklarację :

Tworzy tablicę zawierającą elementy sekwencji.

init<S>(_ s: S) where Element == S.Element, S : Sequence

Dlatego poniższy przykładowy kod Playground pokazuje, jak połączyć dwie tablice typu [Int]w nową tablicę przy użyciu joined()metody i init(_:)inicjalizatora:

let array1 = [1, 2, 3]
let array2 = [4, 5, 6]

let flattenCollection = [array1, array2].joined() // type: FlattenBidirectionalCollection<[Array<Int>]>
let flattenArray = Array(flattenCollection)
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]

# 6. Łączy dwie matryce do nowej tablicy z Array„s reduce(_:_:)metody

Swift Arrayma reduce(_:_:)metodę. reduce(_:_:)ma następującą deklarację :

Zwraca wynik łączenia elementów sekwencji przy użyciu danego zamknięcia.

func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result

Poniższy kod Playground pokazuje, jak połączyć dwie tablice typu [Int]w nową tablicę przy użyciu reduce(_:_:)metody:

let array1 = [1, 2, 3]
let array2 = [4, 5, 6]

let flattenArray = [array1, array2].reduce([], { (result: [Int], element: [Int]) -> [Int] in
    return result + element
})
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]

5
dziękuję za udostępnienie tego kodu, dobre wyjaśnienie, wystarczy dodać do swojej odpowiedzi, najlepiej byłoby, gdybyś powiedział, który z nich jest bardziej wydajny pod względem wydajności?
kokemomuke

Lubię +2 tablice i joined()tablicę tablic.
Cœur

Jeśli scalasz więcej niż 2 tablice (lub łańcuchy lub cokolwiek innego), powstrzymaj się od korzystania z +operatora, generuje to absolutnie szalone czasy kompilacji.
lawicko

@lawicko, którą metodę polecisz?
CyberMew

@CyberMew Wszystko, co nie używa przeciążonych operatorów, podoba mi się metoda nr 3, ponieważ myślę, że jest najbardziej czytelna, ale lubię także metodę nr 4 z płaską mapą. W przypadku ciągów podoba mi się metoda nr 5, ponieważ na końcu otrzymujesz połączony ciąg od razu.
lawicko

34

Jeśli nie jesteś wielkim fanem przeciążania operatora lub po prostu bardziej funkcjonalnym typem:

// use flatMap
let result = [
    ["merge", "me"], 
    ["We", "shall", "unite"],
    ["magic"]
].flatMap { $0 }
// Output: ["merge", "me", "We", "shall", "unite", "magic"]

// ... or reduce
[[1],[2],[3]].reduce([], +)
// Output: [1, 2, 3]

22

Moją ulubioną metodą od czasu Swift 2.0 jest spłaszczenie

var a:[CGFloat] = [1, 2, 3]
var b:[CGFloat] = [4, 5, 6]

let c = [a, b].flatten()

To wróci, FlattenBidirectionalCollectionwięc jeśli chcesz, CollectionTypewystarczy i będziesz miał leniwą ocenę za darmo. Jeśli potrzebujesz dokładnie tablicy, możesz to zrobić:

let c = Array([a, b].flatten())

2
flatten()wydaje się, że już nie istnieje. Ale możesz to rozważyć joined().
Cur

13

Aby uzupełnić listę możliwych alternatyw, reducemożna zastosować implementację zachowania spłaszczania :

var a = ["a", "b", "c"] 
var b = ["d", "e", "f"]

let res = [a, b].reduce([],combine:+)

Najlepszą alternatywą (pod względem wydajności / pamięci) spośród przedstawionych jest po flattenprostu leniwe owijanie oryginalnych tablic bez tworzenia nowej struktury tablic.

Ale zauważ, że spłaszczenie nie zwraca a LazyCollection, więc leniwe zachowanie nie zostanie propagowane do następnej operacji wzdłuż łańcucha (mapa, flatMap, filtr itp.).

Jeśli lazyness sens w danym przypadku, po prostu pamiętać, aby poprzedzić lub dołączania .lazydo flatten(), na przykład, modyfikując Tomasz próbkę w ten sposób:

let c = [a, b].lazy.flatten()

Jak dobrze ta odpowiedź nadal obowiązuje w 2019 r. W przypadku Swift 5.1?
willbattel

flatten () już nie istnieje.
join

4

Jeśli chcesz wstawić drugą tablicę po określonym indeksie, możesz to zrobić (od Swift 2.2):

let index = 1
if 0 ... a.count ~= index {
     a[index..<index] = b[0..<b.count]
}
print(a) // [1.0, 4.0, 5.0, 6.0, 2.0, 3.0] 

4

Swift 3.0

Możesz utworzyć nową tablicę, dodając dwie istniejące tablice z kompatybilnymi typami za pomocą operatora add ( +). Typ nowej tablicy wynika z typu dwóch dodanych razem tablic,

let arr0 = Array(repeating: 1, count: 3) // [1, 1, 1]
let arr1 = Array(repeating: 2, count: 6)//[2, 2, 2, 2, 2, 2]
let arr2 = arr0 + arr1 //[1, 1, 1, 2, 2, 2, 2, 2, 2]

to są prawidłowe wyniki powyższych kodów.


4
var arrayOne = [1,2,3]
var arrayTwo = [4,5,6]

jeśli chcesz wynik jako: [1,2,3, [4,5,6]]

arrayOne.append(arrayTwo)

powyższy kod skonwertuje arrayOne jako pojedynczy element i doda go na końcu arrayTwo.

jeśli chcesz wynik jako: [1, 2, 3, 4, 5, 6], to,

arrayOne.append(contentsOf: arrayTwo)

powyższy kod doda wszystkie elementy arrayOne na końcu arrayTwo.

Dzięki.


4

Swift 4.X

Najprościej wiem, jak użyć znaku +

var Array1 = ["Item 1", "Item 2"]
var Array2 = ["Thing 1", "Thing 2"]

var Array3 = Array1 + Array2

// Array 3 will just be them combined :)

3

Oto najkrótszy sposób na połączenie dwóch tablic.

 var array1 = [1,2,3]
 let array2 = [4,5,6]

Połącz je / połącz

array1 += array2
New value of array1 is [1,2,3,4,5,6]

1

Podobnie w słownikach tablic można:

var dict1 = [String:[Int]]()
var dict2 = [String:[Int]]()
dict1["key"] = [1,2,3]
dict2["key"] = [4,5,6]
dict1["key"] = dict1["key"]! + dict2["key"]!
print(dict1["key"]!)

i możesz iterować po dict1 i dodać dict2, jeśli „klucz” pasuje


0

Marge array, które są różnymi typami danych:

var arrayInt = [Int]()
arrayInt.append(6)
var testArray = ["a",true,3,"b"] as [Any]
testArray.append(someInt)

Wynik :

["a", true, 3, "b", "hi", 3, [6]]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.