Я хотел бы спросить, какой самый дешевый тип данных (с точки зрения потребления памяти и затрат на его хранение / обработку) должен использоваться в качестве фиктивного значения в python dict (для меня важен только ключ из dict, значения являются просто заполнителями)

Например :

d1 = {1: None, 2: None, 3: None}
d2 = {1: -1, 2: -1, 3: -1}
d3 = {1: False, 2: False, 3: False}

Здесь только ключи (1, 2, 3) полезны для меня, значения не так, что они могут быть любым значением (просто используется в качестве заполнителя. То, что я хочу знать, это то, что фиктивные данные я должен использовать здесь. На данный момент я не используйте None, но не уверены, является ли он «самым дешевым».

П.С., я знаю, что лучшим вариантом для хранения только ключей может быть использование Set вместо dict (с фиктивными значениями). Однако причина, по которой я это делаю, заключается в том, что я хочу обмениваться данными между Python и C ++, используя SWIG. А пока я выяснил, как передать Python dict в C ++ как std :: map с помощью SWIG, но не могу найти ничего о том, как передать Python Set в C ++ как std :: set ...

Помощь / рекомендации очень ценятся здесь!

7
Yu Wang 24 Сен 2018 в 18:10

2 ответа

Лучший ответ

Python 3.4 64bit:

>>> import sys
>>> sys.getsizeof(None)
16
>>> sys.getsizeof(False)
24
>>> sys.getsizeof(1)
28
>>> 

Так что None кажется лучшим выбором (я перечислил только неизменяемые объекты и проигнорировал строки и кортежи). Обратите внимание, что это не имеет большого значения, поскольку эти объекты обычно кэшируются, поэтому размер не умножается на количество элементов вашего словаря (кроме того, None гарантированно является одноэлементным )

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

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

Одна из возможных альтернатив - передать представление set как json (тогда в list) как указатель символов на сторону C ++, которая будет анализировать его с помощью хороший парсер json. Если ваши значения не являются большими значениями с плавающей запятой (или огромными целыми числами), это позволит сэкономить память, потому что аспект объекта устраняется с помощью сериализации.

>>> json.dumps(list(set(range(4,10))))
'[4, 5, 6, 7, 8, 9]'  # hard to beat that in terms of size!
5
Jean-François Fabre 24 Сен 2018 в 15:50

Вы можете использовать набор, но SWIG поддерживает только передачу списков Python в качестве параметра set (или использование именованного шаблона) без написания собственной карты типов. Пример (Windows):

< Сильный > test.i *

%module test

%include <std_set.i>
%template(seti) std::set<int>;

%inline %{

#include <set>
#include <iostream>
void func(std::set<int> a)
{
    for(auto i : a)
        std::cout << i << std::endl;
}

%}

Выход:

>>> import set
>>> s = test.seti([1,1,2,2,3,3])  # pass named template
>>> test.func(s)
1
2
3
>>> test.func([1,2,3,3,4,4])  # pass a list that converts to a set
1
2
3
4
>>> test.func({1,1,2,2,3})   # Actual set doesn't work.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: in method 'func', argument 1 of type 'std::set< int,std::less< int >,std::allocator< int > >'
1
Mark Tolonen 28 Сен 2018 в 05:31