Как разработать, а затем проанализировать структуру данных - PullRequest
3 голосов
/ 13 октября 2010

Я разрабатываю программу погоды, в которой мне нужно отслеживать определенные вещи и позволять пользователю добавлять данные, которые будут сохранены и впоследствии прочитаны позже.Мои поля:

Город-штат Zip Metar

Возможно, у меня будет больше данных, которые я хочу сделать с этим файлом конфигурации позже, поэтому я хотел бы, чтобы он имел что-то вроде этого:

[LOCATIONS]
Phoenix:AZ:85001:KPHX
Dallas:TX:75201:KDFW

[USER CONFIGS]
for later

Настройка для записи файла не должна быть очень сложной, просто создайте объект файла для записи, запишите [Locations], а затем данные, которые я планирую хранить в списках, и просто объедините списки с двоеточием..

Тем не менее, я немного озадачен тем, как читать его обратно.

Я знаю, что могу прочитать строку по одной за раз и проверить, является ли строка == '[LOCATIONS] 'например, и читать строки после, пока я не приду к пустой строке, но что, если есть дополнительная пустая строка.Или я должен выполнить старт с ('[') и просто не добавлять пустые строки.

Пытался заняться поиском в Интернете, потому что это выглядит как довольно частая проблема для начинающих программистов, но я пришелпусто (за исключением некоторого изучения модуля CVS, который, как мне кажется, мне здесь не поможет).

Формальная база данных, использующая sqlite, была бы излишней.Максимум, вероятно, будет 20-50 записей для каждого пользователя, большинство будет меньше.

Также в программе каждый элемент данных (кроме состояния), введенный в GUI, может привести к обновлению всех остальных.с правильными значениями.Поскольку почти каждый элемент данных может выступать в роли лидера, я не уверен, как мне следует настроить это для удобного поиска.Должен ли я создать словарь для города, который будет включать структуру вроде {'Dallas' :( 'TX', '75201', 'KDFW')}, чтобы помочь с поиском одного для Metars {'KDFW': ('Dallas', 'TX ',' 75201 ')} и Zips {' 75201 ': (' DALLAS ',' TX ',' KDFW ')}?Это кажется немного лучше, чем итерация по каждой строке для проверки на совпадение, но кажется немного пустой тратой, учитывая, что исходная структура будет таким списком, как ['Dallas', 'TX', '75201', 'KDFW'].То, что было бы неплохо, как словарь-объект, в котором каждый элемент мог бы действовать как ключ, возвращающий другие значения в ассоциации.

Различные мысли и идеи приветствуются.

Ответы [ 5 ]

2 голосов
/ 13 октября 2010

Для хранения данных вы можете использовать XML. Затем прочитайте его, используя любой синтаксический анализатор XML, SAX или DOM, которые включены в Python.

Так как размер данных очень меньше (всего около 20-25 записей на пользователя), вы можете сначала узнать о поисковом термине, о его имени состояния или о пин-коде и т. Д. (Попросите пользователя введите это в GUI).

Предполагая, что данные хранятся в формате [City State Pin Mater], вы можете выполнить поиск в соответствующем столбце. например, если пользователь вводит 12345, и вы знаете, что это пин-код, вам нужно только выполнить поиск в 3-м индексе списка данных и затем вернуть список. Для названия штата вы будете искать во 2-й колонке.

И этот подход работает, даже если число записей велико, скажем, несколько сотен.

1 голос
/ 14 октября 2010

В случае синтаксиса, который вы предложили, есть модуль ConfigParser , таким образом, вы можете легко анализировать файл, получая все строки, сгруппированные по разделам или что угодно.Но позже это приведет к другим проблемам - просто подумайте о массовых обновлениях файла.

Так что я бы рекомендовал использовать sqlite.Это стандартный модуль, и он крошечный, поэтому никаких накладных расходов или дополнительных зависимостей.

0 голосов
/ 16 октября 2010

Что касается структуры данных, я учил себя, как использовать xml.dom. Оказывается, мне действительно это нравится. Теперь я понимаю, почему программисты используют его больше для конфигурационных файлов и т. Д.

Я решил разработать свой собственный класс, который работает как словарь, но может иметь несколько ключей. В отличие от словаря, он может иметь более одного ключа с одинаковым значением (но я разработал метод key (), который будет возвращать только уникальные значения).

Вот код:

#! /usr/bin/python2.6
# -*- coding: utf-8 -*-
'''makes a new dictionary-type class

This class allows for multiple keys unlike the dictionary type.
The keys are past first as a list or tuple. Then, the data is to 
be passed in a tuple or list of tuples or lists with the exact 
number of data items per list/tuple.

Example:

    >>> from superdict import SuperDict
    >>> keynames = ['fname', 'lname', 'street', 'city', 'state', 'zip']
    >>> names = [
    ...     ['Jim', 'Smith', '123 Cherry St', 'Topeka', 'KS', '73135'],
    ...     ['Rachel', 'West', '456 Bossom Rd', 'St Louis', 'MO', '62482']
    ...     ]
    >>> dictionary = SuperDict(keynames, names)

There is a SuperDict.keys method that shows all the keys for a given keyname
to be accessed as in:

    >>> print dictionary.keys('city')
    ['Topeka', 'St Louis']

The add method is used to pass a list/tuple but must have the same number of
'fields'.
    >>> dictionary.add(['John', 'Richards', '6 Tulip Ln', 'New Orleans', 'LA', '69231'])

The extend method is used to pass a multiple lists/tuples inside a list/tuple as above.

    >>> new_names = [
    ['Randy', 'Young', '54 Palm Tree Cr', 'Honolulu', 'HA', '98352'],
    ['Scott', 'People', '31932 5th Ave', 'New York', 'NY', '03152']
    ]
    >>> dictonary.extend(new_names)

The data attribute can be used to access the raw data as in:
    >>> dictionary.data
    [['Jim', 'Smith', '123 Cherry St', 'Topeka', 'KS', '73135'], ['Rachel', 'West', '456 Bossom Rd', 'St Louis', 'MO', '62482'], ['Randy', 'Young', '54 Palm Tree Cr', 'Honolulu', 'HA', '98352'], ['Scott', 'People', '31932 5th Ave', 'New York', 'NY', '03152']]

The data item is retrieved with the find method as below:

    >>> dictionary.find('city', 'Topeka')
    ['Jim', 'Smith', '123 Cherry St', 'Topeka', 'KS', '73135']

What if there are more than one? Use the extended options of find to
find a second field as in:

    >>> dictionary.find('city', 'Topeka', 'state', 'KS')
    ['Jim', 'Smith', '123 Cherry St', 'Topeka', 'KS', '73135']

To find all the fields that match, use findall (second keyname 
is available for this just as in the find method):

    >>> dictionary.find('city', 'Topeka')
    [['Jim', 'Smith', '123 Cherry St', 'Topeka', 'KS', '73135'], ['Ralph', 'Johnson', '513 Willow Way', 'Topeka', 'KS', '73189']]


The delete method allows one to remove data, if needed:
    >>> dictionary.delete(new_names[0])
    >>> dictionary.data
    [['Jim', 'Smith', '123 Cherry St', 'Topeka', 'KS', '73135'], ['Rachel', 'West', '456 Bossom Rd', 'St Louis', 'MO', '62482'], ['Scott', 'People', '31932 5th Ave', 'New York', 'NY', '03152']]

maintainer: <signupnarnie@gmail.com>

LICENSE: GPL version 2
Copywrite 2010
'''

__version__ = 0.4

indexnames = ['city','state','zip','metar']
datasample = [
    ['Pawhuska', 'OK', '74056', 'KBVO'],
    ['Temple', 'TX', '76504', 'KTPL']
    ]


class SuperDict(object):
    '''
    superdict = SuperDict(keynames, data)

    Keynames are a list/tuple of the entry names
    Data is a list/tuple of lists/tuples containing the data1

    All should be of the same length

    See module doc string for more information
    '''

    def __init__(self, indexnames, data=None):
        self.keydict = dict()
        if data:
            self.data = data
        for index, name in enumerate(indexnames):
            self.keydict[name.lower()] = index

    def keys(self, index, sort=False):
        '''
        SuperDict.keys(keyname, sort=False)

        Returns all the "keys" for the keyname(field name) but duplicates
        are removed.

        If sort=True, then the keys are sorted
        '''
        index = index.lower()
        keynames = []
        for item in self.data:
            key = item[self.keydict[index]]
            if key:
                keynames.append(key)
        keynames = list(set(keynames))
        if sort:
            keynames = sorted(keynames)
        return keynames

    def add(self, data):
        '''
        SuperDict.add(list/tuple)

        adds another another entry into the dataset
        '''
        if self.data:
            if not len(data) == len(self.data[0]):
                print 'data length mismatch'
                return
        self.data.append(data)

    def extend(self, data):
        '''
        SuperDict([list1, list2])
        SuperDict((tuple1, tuple2))

        Extends the dataset by more than one field at a time
        '''
        for datum in data:
            self.add(datum)

    def delete(self, data):
        '''
        SuperDict.delete(list/tuple)

        Deletes an entry matching the list or tuple passed to the method
        '''
        # question for later: should I return true or false if something delete or not
        for index, item in enumerate(self.data):
            if data == item:
                del self.data[index]

    def find(self, keyname1, data1, keyname2=None, data2=None):
        '''
        SuperDict(keyname1, data1, keyname2=None, data2=None)

        Look for the first entry based on the value of a keyname(s).
        '''
        keyname1 = keyname1.lower()
        if keyname2:
            keyname2 = keyname2.lower()
        for item in self.data:
            if data1 == item[self.keydict[keyname1]]:
                if not data2:
                    return item
                elif data2 == item[self.keydict[keyname2]]:
                    return item

    def findall(self, keyname1, data1, keyname2=None, data2=None):
        '''
        SuperDict.findall(keyname1, data1, keyname2=None, data2=None)
        '''
        keyname1 = keyname1.lower()
        if keyname2:
            keyname2 = keyname2.lower()
        items = []
        for item in self.data1:
            if data1 == item[self.keydict[keyname1]]:
                if not data2:
                    items.append(item)
                elif data2 == item[self.keydict[keyname2]]:
                    items.append(item)
        return items
0 голосов
/ 13 октября 2010

Я бы не рекомендовал использовать файл в формате ini, который вы опубликовали.

Я думаю, у вас есть два основных варианта: * Использовать базу данных, такую ​​как sqlite, как подсказывает @ ghostdog74 * Использовать плоский файл, используя общую, легко разбираемую структуру данных

Для плоского файла:XML или JSON, вероятно, лучшая ставка.Сейчас есть встроенные парсеры для обоих языков.JSON немного более эффективен, но XML немного более читабелен и структурирован.

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

Вы говорите о эффективном создании собственных индексов, чтобы можно было легко искать по ZIP или метару и т. Д. Я бы посоветовал это не нужно.Если вы ДЕЙСТВИТЕЛЬНО хотели, вы можете использовать хеш-таблицу в памяти для хранения ссылок на объекты, но если вы не читаете файл один раз, а затем выполняете многократный поиск, затраты на создание хеш-таблиц, вероятно, будут намного больше, чем простоцикл, чтобы найти то, что вам нужно.У меня складывается впечатление, что это веб-приложение, в котором вы читаете файл, делаете один или два поиска и выплевываете веб-страницу.

Если ваши данные находятся в точке, когда выполняется цикл по всем записямчто приводит к заметному снижению производительности, и вы попадаете на территорию, где вам следует использовать реальную базу данных, такую ​​как sqlite, mysql, postgresql и т. д. Что угодно, и вы просто заново изобретаете то, что они уже сделалис индексацией и хранением файлов не так хорошо.

0 голосов
/ 13 октября 2010

Вы можете использовать sqlite или любой другой тип баз данных, таких как Mysql и т. Д., Для хранения ваших данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...