Результаты разные для Python и MySQL для аналогичной команды

Я использовал python для создания словаря, но по мере того, как мои данные увеличивались, у меня возникали ошибки памяти, поэтому я решил сэкономить память и просто записать данные в базу данных, но результаты не совпадают. Я думаю, что это связано с поведением defaultdict (но я не уверен).

Вот рабочий код Python (он в основном строит таблицу значений):

from collections import defaultdict
data = [2,5,10]
target_sum = 100
# T[x, i] is True if 'x' can be solved
# by a linear combination of data[:i+1]
T = defaultdict(bool)           # all values are False by default
T[0, 0] = True                # base case

for i, x in enumerate(data):    # i is index, x is data[i]
    for s in range(target_sum + 1): #set the range of one higher than sum to include sum itself
        for c in range(s / x + 1):  
            if T[s - c * x, i]:
                T[s, i+1] = True

#check the python dict results
count = 0
for x in T:
    if T[x] == True:
        print x, ':', T[x]
        count = count +1

print 'total count is ', count
#False is 152 and True is 250.  Total is: 402

Результатом является большая таблица значений (вы можете увидеть разбивку в комментарии. Это правильный результат, который я хочу), но когда я изменяю последнюю строку первого оператора for, добавляемого в базу данных, а не в локальный dict результаты отличаются.

Вот мой модифицированный код, который проблематичен:

cursor = conn.cursor ()
cursor = conn.cursor ()
cursor.execute ("DROP TABLE IF EXISTS data_table")
cursor.execute ("""
    CREATE TABLE data_table
    (
      value     CHAR(80),
      state BOOL
    )
  """)
#with database
for i, x in enumerate(data):    # i is index, x is data[i]
    for s in range(target_sum + 1): #set the range of one higher than sum to include sum itself
        for c in range(s / x + 1):  
            cursor.execute(""" SELECT value, state FROM data_table WHERE value='%s' """ % ([s - c * x, i]))
            if cursor.rowcount == 0:
                #print 'nothing found, adding'
                cursor.execute (""" INSERT INTO data_table (value, state) VALUES ('%s', False)""" % ([s - c * x, i]))
            elif cursor.rowcount == 1:
                cursor.execute (""" UPDATE data_table SET state=True WHERE value = '%s'""" % ([s - c * x, i]))
                #print 'record updated'
    conn.commit()

#False is 17 and True is 286. Total is: 303

Чтобы подвести итог (если вы не хотите запускать код), defaultdict создает ложную запись, когда что-то запрашивается (в данном случае if T[s - c * x, i]:) поэтому для репликации этой функции я выполняю поиск в mysql для значения, и если оно не существует, то я создаю его, если оно существует, тогда я устанавливаю его в значение true. Я очень подозреваю, что не могу правильно воспроизвести функциональность

Единственное, о чем я думал, это то, что Python отображает результаты в виде (222, 0) : False но mysql делает [222,0] не уверенным, если это имеет значение.

1 ответ

Решение

Ваши два примера не обновляют один и тот же ключ:

# First example
if T[s - c * x, i]:
    T[s, i+1] = True
    # Key is (s, i+1)

# Second example
elif cursor.rowcount == 1:
    cursor.execute (""" UPDATE data_table SET state=True WHERE value = '%s'""" % ([s - c * x, i]))
    # Key is (s - c * x, i)

IMO было бы логичнее просто хранить в базе данных истинные случаи, что могло бы упростить вашу программу. В противном случае вам также необходимо проверить, (s, i+1) существует в базе данных, обновите его до True, если он есть, создайте новую строку, если это не так.

PS Я также пропустил команду, где вы установили (0, 0) к Истине. Разве это не должно быть во вставке, сразу после того, как вы создали свою базу данных?

Обновление: также обнаружил еще одну проблему в вашем коде: команда выбора просто проверяет, существует ли строка, а не ее значение. Чтобы правильно повторить ваш первый пример, ваш код должен быть:

cursor.execute (""" INSERT INTO data_table (value, state) VALUES ('%s', True)""" % ([0, 0]))
conn.commit()
# Inserted the (0,0) case
for i, x in enumerate(data):
    for s in range(target_sum + 1):
        for c in range(s / x + 1):  
            cursor.execute(""" SELECT value, state FROM data_table WHERE value='%s' """ % ([s - c * x, i]))
            if cursor.rowcount == 0:
                cursor.execute (""" INSERT INTO data_table (value, state) VALUES ('%s', False)""" % ([s - c * x, i]))
            elif cursor.rowcount == 1:
                (value, state) = cursor.fetchone() # Gets the state
                if state: # equivalent to your if in the first example
                    insertOrUpdate(conn, [s, i+1])
    conn.commit()

Измененные строки прокомментированы.

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

def insertOrUpdate(conn, key):
    cursor.execute(""" SELECT value, state FROM data_table WHERE value='%s' """ % key)
        if cursor.rowcount == 0:
            # Insert as True if not exists
            cursor.execute (""" INSERT INTO data_table (value, state) VALUES ('%s', True)""" % key)
        elif cursor.rowcount == 1:
            (value, state) = cursor.fetchone()
            if !state:
                # Update as True, if it was False
                cursor.execute (""" UPDATE data_table SET state=True WHERE value = '%s'""" % key)

Обновление 3: для сравнения, посмотрите, как программа будет проще, просто сохраняя значения True. Он также использует меньше дискового пространства, занимает меньше времени и ведет себя больше как defaultdict.

cursor = conn.cursor ()
cursor.execute ("DROP TABLE IF EXISTS data_table")
cursor.execute ("""
    CREATE TABLE data_table(
        value     CHAR(80)
    )
""")

cursor.execute (""" INSERT INTO data_table (value) VALUES ('%s')""" % [0, 0])
conn.commit()

for i, x in enumerate(data):    # i is index, x is data[i]
    for s in range(target_sum + 1): #set the range of one higher than sum to include sum itself
        for c in range(s / x + 1):  
            cursor.execute(""" SELECT value FROM data_table WHERE value='%s' """ % ([s - c * x, i]))
            if cursor.rowcount == 1:
                cursor.execute(""" SELECT value FROM data_table WHERE value='%s' """ % [s, i+1])
                if cursor.rowcount == 0:
                    cursor.execute (""" INSERT INTO data_table (value) VALUES ('%s')""" % [s, i+1])
    conn.commit()
Другие вопросы по тегам