2015-03-01 2 views
0

У меня есть массив CKRecords. Каждая запись имеет startTime и Name, среди прочих значений. То, что я хотел бы сделать, это отсортировать записи сначала с помощью уникального startTime, а затем в течение каждого сортировки startTime по уникальному Name.iOS Swift: сортировка массива в многомерный массив

Конечным результатом будет массив, который выглядит следующим образом (я думаю): records = [Date: [Name: [CKRecord]]]

Вот что я прямо сейчас:

func buildIndex(records: [CKRecord]) -> [[CKRecord]] { 
var dates = [NSDate]() 
var result = [[CKRecord]]() 

for record in records { 
    var date = record.objectForKey("startTime") as! NSDate 

    if !contains(dates, date) { 
     dates.append(date) 
    } 
} 

for date in dates { 
    var recordForDate = [CKRecord]() 

    for (index, exercise) in enumerate(exercises) { 
     let created = exercise.objectForKey("startTime") as! NSDate 

     if date == created { 
      let record = exercises[index] as CKRecord 
      recordForDate.append(record) 
     } 
    } 
    result.append(recordForDate) 
} 

return result 
} 

let records = self.buildIndex(data) 

ответ

2

Почему бы не использовать sorted? Как это.

// A simplified version of your `CKRecord` just for demonstration 
struct Record { 
    let time: NSDate 
    let name: String 
} 

let records = [ 
    Record(time: NSDate(timeIntervalSince1970: 1), name: "a"), 
    Record(time: NSDate(timeIntervalSince1970: 2), name: "b"), 
    Record(time: NSDate(timeIntervalSince1970: 1), name: "c"), 
    Record(time: NSDate(timeIntervalSince1970: 3), name: "d"), 
    Record(time: NSDate(timeIntervalSince1970: 3), name: "e"), 
    Record(time: NSDate(timeIntervalSince1970: 2), name: "f"), 
] 

func buildIndex(records: [Record]) -> [[Record]] { 
    var g = [NSDate: [Record]]() 
    for e in records { 
     if (g[e.time] == nil) { 
      g[e.time] = [] 
     } 
     g[e.time]!.append(e) // grouping by `time` 
    } 
    return sorted(g.keys) { (a: NSDate, b: NSDate) in 
     a.compare(b) == .OrderedAscending // sorting the outer array by 'time' 
    } 
    // sorting the inner arrays by `name` 
    .map { sorted(g[$0]!) { $0.name < $1.name } } 
} 

println(buildIndex(records)) 
+0

вы можете написать 'г [e.time] = (г [e.time] ?? []) + [е]' в менее лаконичным способом? Попытка понять эту линию. – colindunn

+0

Это просто добавить элемент в массив в словаре 'g'. – findall

+0

Я получаю ошибку компилятора «Ожидаемый тип» для строки '.map {sorted (g [$ 0]!) ​​{$ 0.name <$ 1.name}}'. Любая идея, что это значит? – colindunn

2

Прежде всего, вы на самом деле не пытается отсортировать массив здесь, вы пытаетесь заказать словарь, который не построен, чтобы быть итерации последовательно. На самом деле, даже если вы сортировать массив первым, а затем построить словарь, как это:

var sortedRecords = [NSDate: [String: CKRecord]]() 
records.sort { return $0.date.timeIntervalSinceDate($1.date) < 0 } 

for record in records { 
    if sortedRecords[record.date] != nil { 
     sortedRecords[record.date] = [String: CKRecord]() 
    } 

    sortedRecords[record.date]![record.name] = record 
} 

заказ не гарантируется, когда вы итерацию над ним в будущем. Тем не менее, словарь - это, по существу, таблица поиска, и элементы могут быть доступны в O (log n) времени. Что вы действительно хотите сделать это либо удалить словарь является благосклонность массив [CKRecord], а затем сортировать так:

records.sort { $0.date.timeIntervalSinceDate($1.date) == 0 ? $0.name < $1.name : $0.date.timeIntervalSinceDate($1.date) < 0 } 

Или, в зависимости от того, что ваша конечная цель, итерацию по диапазону дат, выщипывая записи из словаря, когда вы идете.

+0

Спасибо за это объяснение. Я пытаюсь отобразить записи в двух местах. Сначала в виде таблицы (где мне нужны все записи), а второй - в подробном представлении (где мне нужно только подмножество записей). Моя цель с группировкой состоит в том, чтобы упростить доступ только к необходимой мне информации. Но, возможно, есть лучший способ. – colindunn

+0

Используйте структуру данных, соответствующую конкретной проблеме. Для tableView вы хотите сохранить записи в отсортированном массиве. Для подробного представления конструируйте getter, который преобразует массив в словарь и возвращает его, например: 'lazy var recordsByDate: [NSDate: [String: CKRecord]] {... Метод построения словаря идет здесь ...}' – kellanburket

1

Можно выполнить запрос CloudKit и убедитесь, что вы получите массив, возвращаемый в правильном порядке сортировки, как это:

query.sortDescriptors = [NSSortDescriptor(key: "startTime", ascending: true), NSSortDescriptor(key: "Name", ascending: true)] 

И потом, если вы идете в детальном, вы можете использовать фильтр для получать записи на этот день, как это:

var details = records.filter { (%0.objectForKey("startTime") As! NSDate) == selectedDate } 
Смежные вопросы