Используйте приведенный ниже код для сортировки в алфавитном порядке:
NSArray *unsortedStrings = @[@"Verdana", @"MS San Serif", @"Times New Roman",@"Chalkduster",@"Impact"];
NSArray *sortedStrings =
[unsortedStrings sortedArrayUsingSelector:@selector(compare:)];
NSLog(@"Unsorted Array : %@",unsortedStrings);
NSLog(@"Sorted Array : %@",sortedStrings);
Ниже приведен журнал консоли:
2015-04-02 16:17:50.614 ToDoList[2133:100512] Unsorted Array : (
Verdana,
"MS San Serif",
"Times New Roman",
Chalkduster,
Impact
)
2015-04-02 16:17:50.615 ToDoList[2133:100512] Sorted Array : (
Chalkduster,
Impact,
"MS San Serif",
"Times New Roman",
Verdana
)
Наличие в памяти «таблицы», которая требует поиска, сортировки и произвольной агрегации, действительно требует SQL. Вы сказали, что пробовали SQLite, но понимаете ли вы, что SQLite может использовать базу данных только в памяти?
connection = sqlite3.connect(':memory:')
Затем вы можете создавать / удалять / запрашивать / обновлять таблицы в памяти со всеми функциями SQLite и без файлов, оставшихся, когда все готово. Что касается Python 2.5, sqlite3
находится в стандартной библиотеке, так что это не совсем уж "излишний" IMO.
Вот пример того, как можно создать и заполнить базу данных:
import csv
import sqlite3
db = sqlite3.connect(':memory:')
def init_db(cur):
cur.execute('''CREATE TABLE foo (
Row INTEGER,
Name TEXT,
Year INTEGER,
Priority INTEGER)''')
def populate_db(cur, csv_fp):
rdr = csv.reader(csv_fp)
cur.executemany('''
INSERT INTO foo (Row, Name, Year, Priority)
VALUES (?,?,?,?)''', rdr)
cur = db.cursor()
init_db(cur)
populate_db(cur, open('my_csv_input_file.csv'))
db.commit()
Если вы Если бы вы действительно предпочли не использовать SQL, вам, вероятно, следует использовать список словарей:
lod = [ ] # "list of dicts"
def populate_lod(lod, csv_fp):
rdr = csv.DictReader(csv_fp, ['Row', 'Name', 'Year', 'Priority'])
lod.extend(rdr)
def query_lod(lod, filter=None, sort_keys=None):
if filter is not None:
lod = (r for r in lod if filter(r))
if sort_keys is not None:
lod = sorted(lod, key=lambda r:[r[k] for k in sort_keys])
else:
lod = list(lod)
return lod
def lookup_lod(lod, **kw):
for row in lod:
for k,v in kw.iteritems():
if row[k] != str(v): break
else:
return row
return None
Затем тестирование дает:
>>> lod = []
>>> populate_lod(lod, csv_fp)
>>>
>>> pprint(lookup_lod(lod, Row=1))
{'Name': 'Cat', 'Priority': '1', 'Row': '1', 'Year': '1998'}
>>> pprint(lookup_lod(lod, Name='Aardvark'))
{'Name': 'Aardvark', 'Priority': '1', 'Row': '4', 'Year': '2000'}
>>> pprint(query_lod(lod, sort_keys=('Priority', 'Year')))
[{'Name': 'Cat', 'Priority': '1', 'Row': '1', 'Year': '1998'},
{'Name': 'Dog', 'Priority': '1', 'Row': '3', 'Year': '1999'},
{'Name': 'Aardvark', 'Priority': '1', 'Row': '4', 'Year': '2000'},
{'Name': 'Wallaby', 'Priority': '1', 'Row': '5', 'Year': '2000'},
{'Name': 'Fish', 'Priority': '2', 'Row': '2', 'Year': '1998'},
{'Name': 'Zebra', 'Priority': '3', 'Row': '6', 'Year': '2001'}]
>>> pprint(query_lod(lod, sort_keys=('Year', 'Priority')))
[{'Name': 'Cat', 'Priority': '1', 'Row': '1', 'Year': '1998'},
{'Name': 'Fish', 'Priority': '2', 'Row': '2', 'Year': '1998'},
{'Name': 'Dog', 'Priority': '1', 'Row': '3', 'Year': '1999'},
{'Name': 'Aardvark', 'Priority': '1', 'Row': '4', 'Year': '2000'},
{'Name': 'Wallaby', 'Priority': '1', 'Row': '5', 'Year': '2000'},
{'Name': 'Zebra', 'Priority': '3', 'Row': '6', 'Year': '2001'}]
>>> print len(query_lod(lod, lambda r:1997 <= int(r['Year']) <= 2002))
6
>>> print len(query_lod(lod, lambda r:int(r['Year'])==1998 and int(r['Priority']) > 2))
0
Лично мне больше нравится версия SQLite, поскольку она лучше сохраняет ваши типы (без дополнительного кода преобразования в Python) и легко расширяется для соответствия будущим требованиям. Но опять же, мне вполне комфортно с SQL, поэтому YMMV.
Иметь класс таблицы, строки которого представляют собой список объектов строк dict или лучше
В таблице не добавляются строки напрямую, но есть метод, который обновляет несколько карт поиска, например, для имени если вы не добавляете строки по порядку или id не являются последовательными, вы также можете использовать idMap например
class Table(object):
def __init__(self):
self.rows = []# list of row objects, we assume if order of id
self.nameMap = {} # for faster direct lookup for row by name
def addRow(self, row):
self.rows.append(row)
self.nameMap[row['name']] = row
def getRow(self, name):
return self.nameMap[name]
table = Table()
table.addRow({'ID':1,'name':'a'})
First, given that you have a complex data retrieval scenario, are you sure even SQLite is overkill?
You'll end up having an ad hoc, informally-specified, bug-ridden, slow implementation of half of SQLite, paraphrasing Greenspun's Tenth Rule.
That said, you are very right in saying that choosing a single data structure will impact one or more of searching, sorting or counting, so if performance is paramount and your data is constant, you could consider having more than one structure for different purposes.
Above all, measure what operations will be more common and decide which structure will end up costing less.
Лично я бы использовал список списков строк. Поскольку данные для каждой строки всегда находятся в одном и том же порядке, вы можете легко сортировать по любому из столбцов, просто обращаясь к этому элементу в каждом из списков. Вы также можете легко подсчитывать на основе определенного столбца в каждом списке, а также выполнять поиск. По сути, это максимально приближено к двумерному массиву.
На самом деле единственный недостаток здесь заключается в том, что вам нужно знать, в каком порядке находятся данные, и если вы измените этот порядок, вам придется изменить свой процедуры поиска / сортировки для соответствия.
Еще одна вещь, которую вы можете сделать, - это иметь список словарей.
rows = []
rows.append({"ID":"1", "name":"Cat", "year":"1998", "priority":"1"})
Это позволит избежать необходимости знать порядок параметров, чтобы вы могли просматривать каждое поле «год» в списке .