Como concatenar ou mesclar matrizes no Swift?

396

Se houver duas matrizes criadas rapidamente, assim:

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

Como eles podem ser mesclados [1, 2, 3, 4, 5, 6]?

Hristo
fonte
Este é um subconjunto de stackoverflow.com/q/24465281/78336
neoneye

Respostas:

691

Você pode concatenar as matrizes +, criando uma nova matriz

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

ou anexar uma matriz à outra com +=(ou 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]
Martin R
fonte
[AnyObect]? não é idêntico ao CGFloat. Ao concatenar para matrizes AnyObject.
khunshan
6
Khunshan: AnyObjectindica um objeto que, pelo que entendi, significa algo que é instanciado a partir de um tipo de classe. CGFloatnão é um objeto, é um valor escalar. Pelo que entendi, as matrizes podem conter escalares, a menos que sejam definidas como contendo AnyObjectou sejam mais refinadas. No entanto, suspeito que aqui o problema é que a matriz está agrupada em um opcional, então você deve desembrulhá-la com !ou ?primeiro.
Owen Godfrey
Sabemos se a inteligência Copy-On-Write do Swift 2 se estende para determinar se a bparte de aé modificada (portanto, possivelmente excluindo uma cópia de bdurante a.appendContentsOf(b))?
Ephemera
11
@OwenGodfrey thanks. Tenho lil confusão sobre appendContentsOf e insertContentsOf.
khunshan
137

Com o Swift 5, de acordo com suas necessidades, você pode escolher uma das seis maneiras a seguir para concatenar / mesclar duas matrizes.


# 1 Mesclar duas matrizes em uma nova matriz com Arrayo +(_:_:)operador genérico de

Arraypossui um +(_:_:)operador genérico. +(_:_:)tem a seguinte declaração :

Cria uma nova coleção concatenando os elementos de uma coleção e uma sequência.

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

O seguinte código de exemplo do Playground mostra como mesclar duas matrizes do tipo [Int]em uma nova matriz usando o +(_:_:)operador genérico:

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

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

# 2 Anexe os elementos de uma matriz a uma matriz existente com Arrayo +=(_:_:)operador genérico de

Arraypossui um +=(_:_:)operador genérico. +=(_:_:)tem a seguinte declaração :

Anexa os elementos de uma sequência a uma coleção substituível por intervalo.

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

O seguinte código de exemplo do Playground mostra como anexar os elementos de uma matriz do tipo [Int]em uma matriz existente usando o +=(_:_:)operador genérico:

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

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

# 3 Anexar uma matriz a outra matriz com Arrayo append(contentsOf:)método

Swift Arraytem um append(contentsOf:)método. append(contentsOf:)tem a seguinte declaração :

Adiciona os elementos de uma sequência ou coleção ao final desta coleção.

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

O seguinte código de exemplo do Playground mostra como anexar uma matriz a outra matriz do tipo [Int]usando o append(contentsOf:)método:

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

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

# 4 Mesclar duas matrizes em uma nova matriz com Sequenceo flatMap(_:)método de

O Swift fornece um flatMap(_:)método para todos os tipos que estão em conformidade com o Sequenceprotocolo (inclusive Array). flatMap(_:)tem a seguinte declaração :

Retorna uma matriz que contém os resultados concatenados da chamada da transformação fornecida com cada elemento dessa sequência.

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

O seguinte código de exemplo do Playground mostra como mesclar duas matrizes do tipo [Int]em uma nova matriz usando o flatMap(_:)método:

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 Mesclar duas matrizes em uma nova matriz com Sequenceo joined()método e Arrayo init(_:)inicializador

O Swift fornece um joined()método para todos os tipos que estão em conformidade com o Sequenceprotocolo (inclusive Array). joined()tem a seguinte declaração :

Retorna os elementos dessa sequência de seqüências, concatenados.

func joined() -> FlattenSequence<Self>

Além disso, Swift Arraytem um init(_:)inicializador. init(_:)tem a seguinte declaração :

Cria uma matriz que contém os elementos de uma sequência.

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

Portanto, o seguinte código de exemplo do Playground mostra como mesclar duas matrizes do tipo [Int]em uma nova matriz usando o joined()método e o init(_:)inicializador:

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 Mesclar duas matrizes em uma nova matriz com Arrayo reduce(_:_:)método de

Swift Arraytem um reduce(_:_:)método. reduce(_:_:)tem a seguinte declaração :

Retorna o resultado da combinação dos elementos da sequência usando o fechamento fornecido.

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

O seguinte código do Playground mostra como mesclar duas matrizes do tipo [Int]em uma nova matriz usando o reduce(_:_:)método:

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]
Imanou Petit
fonte
5
obrigado por compartilhar esse código, boa explicação, apenas adição à sua resposta, seria melhor se você dissesse qual é o mais eficiente no desempenho?
Kokemomuke 31/01
Eu gosto +de 2 matrizes e joined()de uma matriz de matrizes.
Cœur
Se você estiver mesclando mais de 2 matrizes (ou cadeias de caracteres ou qualquer outra coisa), evite usar o +operador, isso gera tempos de compilação absolutamente insanos.
lawicko
@lawicko qual método você recomendará?
CyberMew
@ CyberMew Qualquer coisa que não use operadores sobrecarregados, gosto do método 3, porque acho que é mais legível, mas também gosto do método 4, com o mapa plano. Para strings, eu gosto do método 5, porque no final você obtém a string unida imediatamente.
lawicko
34

Se você não é um grande fã de sobrecarga de operador ou apenas um tipo funcional:

// 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]
Mazyod
fonte
22

Meu método favorito desde o Swift 2.0 é achatar

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

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

Isso retornará, FlattenBidirectionalCollectionportanto, se você quiser apenas CollectionTypeisso, será suficiente e terá uma avaliação preguiçosa gratuitamente. Se você precisar exatamente da matriz, poderá fazer o seguinte:

let c = Array([a, b].flatten())
Tomasz Bąk
fonte
2
flatten()parece não existir mais hoje em dia. Mas você pode considerar joined().
Cœur
13

Para completar a lista de possíveis alternativas, reducepoderia ser usado para implementar o comportamento de achatar :

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

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

A melhor alternativa (desempenho / memória) entre as apresentadas é simplesmente flattenque apenas empacota as matrizes originais preguiçosamente sem criar uma nova estrutura de matriz.

Mas observe que o achatamento não retorna a LazyCollection, para que o comportamento lento não seja propagado para a próxima operação ao longo da cadeia (mapa, flatMap, filtro, etc ...).

Se a preguiça fizer sentido no seu caso específico, lembre-se de acrescentar ou anexar a .lazypara flatten(), por exemplo, modificar a amostra do Tomasz desta maneira:

let c = [a, b].lazy.flatten()
Umberto Raimondi
fonte
Até que ponto essa resposta ainda permanece em 2019 com o Swift 5.1?
willbattel
flatten () não existe mais.
join
4

Se você deseja que a segunda matriz seja inserida após um índice específico, você pode fazer isso (a partir do 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] 
Vitalii
fonte
4

Swift 3.0

Você pode criar uma nova matriz adicionando duas matrizes existentes com tipos compatíveis ao operador de adição ( +). O tipo da nova matriz é deduzido do tipo das duas matrizes que você adiciona,

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]

este é o resultado certo dos códigos acima.

Lorem Ipsum Dolor
fonte
4
var arrayOne = [1,2,3]
var arrayTwo = [4,5,6]

se você deseja resultado como: [1,2,3, [4,5,6]]

arrayOne.append(arrayTwo)

O código acima converterá arrayOne como um único elemento e o adicionará ao final de arrayTwo.

se você deseja resultado como: [1, 2, 3, 4, 5, 6], então,

arrayOne.append(contentsOf: arrayTwo)

O código acima adicionará todos os elementos de arrayOne no final de arrayTwo.

Obrigado.

meMadhav
fonte
4

Swift 4.X

A maneira mais fácil que eu sei é usar o sinal +

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

var Array3 = Array1 + Array2

// Array 3 will just be them combined :)
Stotch
fonte
3

Aqui está a maneira mais curta de mesclar duas matrizes.

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

Concatenar / mesclar eles

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

Da mesma forma, com dicionários de matrizes, pode-se:

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"]!)

e você pode iterar sobre dict1 e adicionar dict2 se a "chave" corresponder

Jeremy Andrews
fonte
0

Marge array que são diferentes tipos de dados:

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

Resultado :

["a", true, 3, "b", "hi", 3, [6]]
Abhishek Gupta
fonte