0

Swift 2.1 を使用して、辞書の配列をキー dateKey の日付値でソートする関数を作成しようとしています。

これを Array 型の拡張として追加したいので、次を使用して呼び出すことができますsomeArray.sortDictionariesByDate(dateKey: String, dateFormatter: NSDateFormatter)

extension Array where Element: CollectionType {
  mutating func sortDictionariesByDate(dateKey: String, dateFormatter: NSDateFormatter) {
    sortInPlace {
      dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
      if let dateStringA: String = ($0 as? [String: AnyObject])?[dateKey] as? String, let dateStringB = ($1 as? [String: AnyObject])?[dateKey] as? String {
        if let dateA: NSDate = dateFormatter.dateFromString(dateStringA), dateB: NSDate = dateFormatter.dateFromString(dateStringB) {
          return dateA.compare(dateB) == .OrderedAscending
        }
      }
      return false
    }
  }
}

これは、辞書の型が である限り問題なく動作しますが[String: AnyObject]、型の辞書で使用すると、にキャストできないため機能し[String: String]ません。これは がではないためだと思います。代わりに要素を型キャストしようとしましたが、型または型の辞書を使用しても機能しません。StringAnyObjectStringStructClass[String: Any][String: AnyObject][String: String]

キーの型Stringと任意の値の型 (など) を持つ辞書をサポートするために使用できるキャストStringAnyObjectまたは完全にキャストを回避するために拡張機能に追加できる where 句またはプロトコルの適合性はありますか?

編集:リクエストごとに2つの例の配列を次に示します

var sampleArray1: [[String: AnyObject]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
sampleArray1.sortDictionariesByDate("date", dateFormatter: NSDateFormatter())
var sampleArray2: [[String: String]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
sampleArray2.sortDictionariesByDate("date", dateFormatter: NSDateFormatter())
4

3 に答える 3

2

最初の問題: 日付ではなく、文字列を比較しています。幸いなことに、文字列の形式により、文字列とそれが表す日付値の両方として直接比較できます。したがって、まったく変換する必要はありませんNSDate

2 番目の問題は、が共変であっても、卸売Dictionary<Key,Value1>への型キャストがDictionary<Key,Value2>機能しないことです。このような些細な例ではうまくいくかもしれません...Value1Value2

let a : [String: String] = ["name": "David", "location": "Chicago"]
let b = a as [String: AnyObject]

...コンパイラは値の型 ( String)aを認識し、コンパイル時に最適化できるためです。あなたのような動的な状況では、事前に入手できる情報はありません。


ダイナミズムが必要な場合は、いつでも古くからの友人である Objective-C に戻ることができます。

extension Array where Element: CollectionType {
    mutating func sortDictionariesByDate(dateKey: String) {
        self.sortInPlace {
            if let a = $0 as? NSDictionary, b = $1 as? NSDictionary {
                return (a[dateKey] as? String) < (b[dateKey] as? String)
            } else {
                return false
            }
        }
    }
}

// Example:
var sampleArray1: [[String: AnyObject]] = [
    ["date": "2015-10-24T13:00:00.000Z", "foo": "bar"],
    ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
    ["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]
var sampleArray2: [[String: String]] = [
    ["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], 
    ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
    ["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]

sampleArray1.sortDictionariesByDate("date")
sampleArray2.sortDictionariesByDate("date")

日付ではなく文字列を比較しているため、noNSDateFormatterは必要ないことに注意してください。

于 2015-10-22T20:42:33.520 に答える
1

あなたが求めていることはばかげています。キャストなしで両方[[String:AnyObject]]で機能する単一の関数を作成するつもりはありません。[[String:String]]Swift には厳密な型付けがあります。それがまさにその通りです。キャストして幸せになろう!

ディクショナリのような複雑な型の配列をキャストするコツは、map各要素を個別にキャストすることです (これは実際に、配列のキャストが舞台裏で行うことです):

let sampleArray1: [[String: AnyObject]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]
let sampleArray2: [[String: String]] = [["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"]]

func sortByDate(arr:[[String:AnyObject]]) -> [[String:AnyObject]] {
    let result = arr.sort {
        d1, d2 in
        let dat1 = NSDateFormatter().dateFromString(d1["date"] as! String)!
        let dat2 = NSDateFormatter().dateFromString(d2["date"] as! String)!
        return dat1.timeIntervalSinceReferenceDate < dat2.timeIntervalSinceReferenceDate
    }
    return result
}

let arr1 = sortByDate(sampleArray1)
let arr2 = sortByDate(sampleArray2.map{$0 as [String:AnyObject]})
// and if you have to, `map` arr2 back down to [String:String]

仕様を完全に埋めていないことは認めますが、キー名とフォーマッタを指定できるようにパラメータを追加するのは簡単です。一致する日付形式がないため、この例では実際にデータがクラッシュすることに注意してください。有効な形式を指定する必要があります。

また、(同じ点の一部として)実際の日付ではなく日付文字列を辞書に入れるのはばかげていると思います。しかし、私は議論のためだけにその前提に沿ってきました。

于 2015-10-22T20:59:58.120 に答える
0

Arrayこれは、関数内でキャストを処理しながら関数を拡張として保持する別のソリューションです。これ.map()により、さまざまな種類の辞書を処理するときに前後に使用する必要がなくなります。欠点は、関数でサポートされている型を事前に知っておく必要があることですが、 @matt のソリューションでは、メソッドを呼び出すときにキャストを処理できますが、拡張機能ではなく、その場での並べ替えやマッピングを行わず、前方へ。

extension Array where Element: CollectionType {
  mutating func sortDictionariesByDate(dateKey: String, dateFormatter: NSDateFormatter) {
    sortInPlace {
      dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
      var dateString1: String?
      var dateString2: String?

      if let a = $0 as? [String: AnyObject], let b = $1 as? [String: AnyObject] {
        if let dateStringA: String = a[dateKey] as? String, dateStringB: String = b[dateKey] as? String {
          dateString1 = dateStringA
          dateString2 = dateStringB
        }
      } else if let a = $0 as? [String: String], let b = $1 as? [String: String] {
        dateString1 = a[dateKey]
        dateString2 = b[dateKey]
      }

      if let dateString1: String = dateString1, let dateString2: String = dateString2 {
        if let date1: NSDate = dateFormatter.dateFromString(dateString1), date2: NSDate = dateFormatter.dateFromString(dateString2) {
          return date1.timeIntervalSinceReferenceDate < date2.timeIntervalSinceReferenceDate
        }
      }
      return false
    }
  }
}

// Example:
var sampleArray1: [[String: AnyObject]] = [
    ["date": "2015-10-24T13:00:00.000Z", "foo": "bar"],
    ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
    ["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]
var sampleArray2: [[String: String]] = [
    ["date": "2015-10-24T13:00:00.000Z", "foo": "bar"], 
    ["date": "2015-10-24T14:00:00.000Z", "foo": "bar"],
    ["date": "2015-10-24T10:00:00.000Z", "foo": "bar"]
]

sampleArray1.sortDictionariesByDate("date")
sampleArray2.sortDictionariesByDate("date")
于 2015-10-22T22:17:51.387 に答える