2017-01-15 15 views
4

私は自分のプロジェクトにswiftを使っています。配列にある構造体の値を変更するにはどうすればよいですか?

私はInstrumentという名前の構造体の配列を持っています。後で配列から特定のInstrumentを返す関数を作った。それから、そのプロパティの値を変更したいのですが、この変更は配列内には反映されません。

内部の要素のすべての変更を含めるには、この配列が必要です。ここでベストプラクティスは何と思いますか?

  • classからstructから変更Instrument
  • 配列からInstrumentを返す関数を何とか書き換えます。

今私は、この関数を使用します。

func instrument(for identifier: String) -> Instrument? { 
    if let instrument = instruments.filter({ $0.identifier == identifier }).first { 
    return instrument 
    } 
    return nil 
} 

迅速に構造体のための言語であることが知られているので、私は構造体で始まり、私はclassstructを使用する際に学びたいです。

おかげ

+1

'filter(_ :)'と 'first'ではなく' first(where:) 'を使うことができます。 – Hamish

+2

構造体は値型です。プロパティを変更したら、アイテムを配列に戻す必要があります。しかし、フレームワークと戦わないでください!参照型が必要な場合は、クラスを使用します。 – vadian

+0

これを見てください:http://stackoverflow.com/a/26375105/312312 – Lefteris

答えて

8

を構造体のインストゥルメントの配列を使用すると、取得することができます特定の識別子を持つインストゥルメントのインデックスを取得し、インストゥルメントのプロパティにアクセスして変更するために使用します。

struct Instrument { 
    let identifier: String 
    var value: Int 
} 

var instruments = [ 
    Instrument(identifier: "alpha", value: 3), 
    Instrument(identifier: "beta", value: 9), 
] 

if let index = instruments.index(where: { $0.identifier == "alpha" }) { 
    instruments[index].value *= 2 
} 

print(instruments) // [Instrument(identifier: "alpha", value: 6), Instrument(identifier: "beta", value: 9)] 
1

あなたは値型のアプローチに固執する(とidentifierが一意でないことを考える:それ以外の場合は、簡単な抽出と置換ロジック用の辞書を使用することを検討してください)場合は、に変異関数を書くことができます[Instruments]配列を所有する型で、配列内の(最初の)Instrumentインスタンスを見つけて、指定されたクロージャを使用してそれを変更します。例えば。 (改善のおかげ@Hamish!):

struct Instrument { 
    let identifier: String 
    var changeThis: Int 
    init(_ identifier: String, _ changeThis: Int) { 
     self.identifier = identifier 
     self.changeThis = changeThis 
    } 
} 

struct Foo { 
    var instruments: [Instrument] 

    @discardableResult // do not necessarily make use of the return result (no warning if not) 
    mutating func updateInstrument(forFirst identifier: String, 
      using mutate: (inout Instrument) ->()) -> Bool { 
     if let idx = instruments.indices 
      .first(where: { instruments[$0].identifier == identifier }) { 

      // mutate this instrument (in-place) using supplied closure 
      mutate(&instruments[idx]) 

      return true // replacement successful 
     } 
     return false // didn't find such an instrument 
    } 
} 

使用例:@Owen:s answerに示すよう

var foo = Foo(instruments: 
    [Instrument("a", 1), Instrument("b", 2), 
    Instrument("c", 3), Instrument("b", 4)]) 

// make use of result of call 
if foo.updateInstrument(forFirst: "b", using: { $0.changeThis = 42 }) { 
    print("Successfully mutated an instrument") 
} // Successfully mutated an instrument 

// just attempt mutate and discard the result 
foo.updateInstrument(forFirst: "c", using: { $0.changeThis = 99 }) 

print(foo.instruments) 
/* [Instrument(identifier: "a", changeThis: 1), 
    Instrument(identifier: "b", changeThis: 42), 
    Instrument(identifier: "c", changeThis: 99), 
    Instrument(identifier: "b", changeThis: 4)] */ 

、素子上の特定の述語のための最初のインデックスを見つけるためにもすっきりアプローチ配列のindex(where:)メソッドを使用しています(前述のようにindices.first(where:)ではなく)。完全な例でindex(where:)アプローチを用いて、上記単にFooupdateInstrument(forFirst:using)方法で

if let idx = instruments 
    .index(where: { $0.identifier == identifier }) { ... 

if let idx = instruments.indices 
    .first(where: { instruments[$0].identifier == identifier }) { ... 

を交換に対応します。我々はさらに、単一の行に(可能性)の交換やboolean型の戻りを実行するためにOptionalmap機能を適用することにより、updateInstrument(forFirst:using)方法を凝縮でき

struct Foo { 
    var instruments: [Instrument] 

    @discardableResult 
    mutating func updateInstrument(forFirst identifier: String, 
     using mutate: (inout Instrument) ->()) -> Bool { 
     return instruments 
      .index(where: { $0.identifier == identifier }) 
      .map { mutate(&instruments[$0]) } != nil 
    } 
} 
関連する問題