Как корректно сравнить 2 массива?

Рейтинг: 0Ответов: 1Опубликовано: 26.04.2023

Подскажите пожалуйста, каким образом правильней сравнивать 2 массива данных, ndarray и tuple?

Задача простая - сравнить 2 массива на идентичность. Если есть отличия, заменить старое значение на новое. Значения датафрейма ниже соответствуют значениям в таблице БД

    dataframe = {'id': {0: 7169458, 1: 7169459, 2: 7169460},
                 'article': {0: 'БАК.00037', 1: 'БАК.00029', 2: 'БАК.00026'}, 
                 'recommended_price': {0: 4500.0, 1: 1595.0, 2: 1261.0}, 
                 'marketing_price': {0: '5241.0000', 1: '1455.0000', 2: '1060.0000'},
                 'old_price': {0: '10377.0000', 1: '2927.0000', 2: '2104.0000'},
                 'premium_price': {0: '', 1: '', 2: ''}, 
                 'price': {0: '6226.0000', 1: '1756.0000', 2: '1262.0000'}, 
                 'min_price': {0: '6226.0000', 1: '1756.0000', 2: '1262.0000'}, 
                 'price_index': {0: 'AVG_PROFIT', 1: 'PROFIT', 2: 'PROFIT'},
                 'external_minimal_price': {0: '5959.0000', 1: '1753.0000', 2: '1261.0000'},
                 'external_price_index_value': {0: 1.04, 1: 1.0, 2: 1.0}, 
                 'ozon_minimal_price': {0: '', 1: '', 2: ''},
                 'ozon_price_index_value': {0: 0.0, 1: 0.0, 2: 0.0}, 
                 'self_marketplaces_minimal_price': {0: '6223.0000', 1: '1753.0000', 2: '1261.0000'}, 
                 'self_marketplaces_price_index_value': {0: 1.0, 1: 1.0, 2: 1.0}}

При выполнении следующего метода вывод показывает, что отличаются все строки таблицы:

import psycopg2
import numpy as np
import functools
    

def update_items_prices(self, tname, schema=None):
    dataframe = pd.DataFrame(dataframe)
    values = dataframe.to_numpy()

   with self.connection.cursor() as cursor:
        cursor.execute(f"SELECT article FROM {schema}.{tname}")
        list_items_db = cursor.fetchall()
        list_items_db = [i[0] for i in list_items_db]
        cursor.execute(f"""SELECT  column_name FROM information_schema.columns WHERE table_schema = '{schema}' AND table_name = '{tname}'; """)
        column_name_list = cursor.fetchall()

        # Update table
        # Check count of articles
        if set(list_items_db) == set(values[:, 1]):
            row_updated = [0, 0]
            with self.connection.cursor() as cursor:
                for i in values:
                    cursor.execute(f"SELECT * FROM {schema}.{tname} WHERE article='{i[1]}';")
                    row = cursor.fetchall()
                    if not functools.reduce(lambda x, y: x and y, map(lambda p, q: p==q, row[0], tuple(i)), True):

                        print("******", row[0], tuple(i), "*******", sep="\n")

                        row_updated[0] += 1
                        for cell, new_cell, column_name in zip(row[0], tuple(i), tuple(column_name_list)):
                            if cell != new_cell:
                                row_updated[1] += 1
                                # cursor.execute(f"""UPDATE {schema}.{tname} SET {column_name[0]}='{new_cell}' WHERE article='{i[1]}'""")
            print(f"Total updated: {row_updated[0]} rows. Values updated: {row_updated[1]}.")

Вывод:

******
(7169458, '1111111', Decimal('4500.00'), Decimal('5241.00'), Decimal('10377.00'), Decimal('NaN'), Decimal('6226.00'), Decimal('6226.00'), 'AVG_PROFIT', Decimal('5959.00'), Decimal('1.04'), Decimal('NaN'), Decimal('0.00'), Decimal('6223.00'), Decimal('1.00'))

(7169458, '1111111', 4500.0, 5241.0, 10377.0, nan, 6226.0, 6226.0, 'AVG_PROFIT',
 5959.0, 1.04, nan, 0.0, 6223.0, 1.0)
*******
(7169459, '2222222', Decimal('1595.00'), Decimal('1455.00'), Decimal('2927.00'), Decimal('NaN'), Decimal('1756.00'), Decimal('1756.00'), 'PROFIT', Decimal('1753.00'), Decimal('1.00'), Decimal('NaN'), Decimal('0.00'), Decimal('1753.00'), Decimal('1.00'))

(7169459, '2222222', 1595.0, 1455.0, 2927.0, nan, 1756.0, 1756.0, 'PROFIT',
 1753.0, 1.0, nan, 0.0, 1753.0, 1.0)
*******
(7169460, '333333', Decimal('1261.00'), Decimal('1060.00'), Decimal('2104.00'), Decimal('NaN'), Decimal('1262.00'), Decimal('1262.00'), 'PROFIT', Decimal('1261.00'), Decimal('1.00'), Decimal('NaN'), Decimal('0.00'), Decimal('1261.00'), Decimal('1.00'))

(7169460, '333333', 1261.0, 1060.0, 2104.0, nan, 1262.0, 1262.0, 'PROFIT',
 1261.0, 1.0, nan, 0.0, 1261.0, 1.0)

Попытки привести к одному типу данных, к примеру строку из БД преобразовать в np.ndarray приводят к исключению TypeError. Подскажите пожалуйста как нужно сравнивать такие фреймы. Какие практики сравнения лучше?

Ответы

▲ 1Принят

В общем, я вам написал, как можно сделать сравнение. Проще не получается, потому что есть проблемы при сравнении Decimal('NAN') и numpy.nan, а также при сравнении Decimal(1.04) и 1.04:

from decimal import Decimal
import numpy as np
from numpy import nan

x = (7169458, '1111111', Decimal('4500.00'), Decimal('5241.00'), Decimal('10377.00'), Decimal('NaN'), Decimal('6226.00'), Decimal('6226.00'), 'AVG_PROFIT', Decimal('5959.00'), Decimal('1.04'), Decimal('NaN'), Decimal('0.00'), Decimal('6223.00'), Decimal('1.00'))
y = (7169458, '1111111', 4500.0, 5241.0, 10377.0, nan, 6226.0, 6226.0, 'AVG_PROFIT', 5959.0, 1.04, nan, 0.0, 6223.0, 1.0)

print(x == y)
print(all(a == b or (isinstance(a, Decimal) and (float(a) == b or (a.is_nan() and np.isnan(b)))) for a, b in zip(x, y)))

Вывод:

False
True