index(of:)
(このメソッドは非推奨となり、firstIndex(of)
を推奨)に与えることができる引数は、Equatable
プロトコルに準拠している必要があります(内部で要素の比較を行うため)。
しかし、辞書に含まれているAny
型は具体的な型(concrete type
)がないため比較することができないためエラーとなります。
辞書(Dictionary
)をEquatable
にできるか否かは私の知識ではわかりませんでした。
一番簡単なのは、前回のご質問で ch3cooh さんがご指摘のように、データを構造体として扱い、その構造体をEquatable
に準拠させることです。
準拠させることで、以下のような処理が可能となります。
swift
1 struct User : Equatable {
2 let name : String
3 let age : Int
4 let height : Int
5 }
6
7 let dicArray : [ User ] = [
8 User ( name : "田中" , age : 45 , height : 167 ) ,
9 User ( name : "佐藤" , age : 44 , height : 180 ) ,
10 User ( name : "鈴木" , age : 44 , height : 177 ) ,
11 User ( name : "高橋" , age : 45 , height : 169 ) ,
12 User ( name : "黒田" , age : 44 , height : 172 ) ,
13 User ( name : "山本" , age : 44 , height : 179 )
14 ]
15
16 let dic = dicArray [ 3 ]
17
18 if let firstIndex = dicArray . firstIndex ( of : dic ) {
19 // インデックス番号が表示される
20 print ( firstIndex )
21 }
辞書のvalue
がAny
型になってしまうとその後の扱いがやや厄介(キャストが増える)なので、やはり構造体を使って処理されるのが見通しが良くなるのではないかと思います。
辞書を使ったままインデックスを求める方法と、抽出したデータから元のデータを書き換える方法も考えていたので、そちらも載せておきます。
もちろん、辞書を構造体に書き換えれば同じようなロジックでいけるはずです。
もっといい方法があるかもしれませんが、参考になれば幸いです。
Playgound で実行できるようになっています。
swift
1 import UIKit
2
3 var dicArray : [ [ String : Any ] ] = [ [ "name" : "田中" , "age" : 45 , "height" : 167 ] ,
4 [ "name" : "佐藤" , "age" : 44 , "height" : 180 ] ,
5 [ "name" : "鈴木" , "age" : 44 , "height" : 177 ] ,
6 [ "name" : "高橋" , "age" : 45 , "height" : 169 ] ,
7 [ "name" : "黒田" , "age" : 44 , "height" : 172 ] ,
8 [ "name" : "山本" , "age" : 44 , "height" : 179 ] ]
9
10 func pickup ( array : [ [ String : Any ] ] ) - > [ [ String : Any ] ] {
11 return array . filter { ( e ) - > Bool in
12 return ( e [ "age" ] as ! Int ) == 44
13 } . sorted { ( x , y ) - > Bool in
14 return ( x [ "height" ] as ! Int ) < ( y [ "height" ] as ! Int )
15 }
16 }
17
18 // tableView を表示したつもり
19 func printTable ( array : [ [ String : Any ] ] , title : String = "" ) {
20 print ( title )
21 for col in array {
22 print ( col )
23 }
24 print ( "" )
25 }
26
27 // 指定秒数待つ
28 func waitSec ( sec : Double ) {
29 Thread . sleep ( forTimeInterval : sec )
30 }
31
32 // ここから本題
33 // オリジナルを表示
34 printTable ( array : dicArray , title : "** original **" )
35 waitSec ( sec : 2.0 )
36
37 // 原本から44歳のみをコピー
38 var dicArray2 = pickup ( array : dicArray )
39
40 // tableView に表示したつもり
41 printTable ( array : dicArray2 , title : "** tableView **" )
42 waitSec ( sec : 2.0 )
43
44 // 「山本」さんのみ変更する -> オリジナルのデータを変更する
45 // オリジナルから、山本さんが含まれる最初のインデックスを得る
46 let target = "山本"
47 guard let index = dicArray . firstIndex ( where : { ( $ 0 [ "name" ] as ! String ) . contains ( target ) } ) else {
48 // 目的の名前が見つからなかった場合。
49 // ここでは処理の都合fatalError で強制的に落としているが、実際は適切に処理する
50 fatalError ( "(target) さんは見つかりませんでした" )
51 }
52 print ( "(target)さんのデータを書き換えます。" )
53 print ( "index: (index)" )
54
55 // オリジナルから更新したいデータを更新
56 dicArray [ index ] . updateValue ( 45 , forKey : "age" )
57 dicArray [ index ] . updateValue ( 171 , forKey : "height" )
58 waitSec ( sec : 2.0 )
59
60 // 書き換えたあとのオリジナルを表示
61 printTable ( array : dicArray , title : "** original **" )
62 waitSec ( sec : 2.0 )
63
64 // オリジナルから44歳のみをコピー
65 dicArray2 = pickup ( array : dicArray )
66
67 // tableView に表示したつもり
68 printTable ( array : dicArray2 , title : "** tableView **" )