2014-09-29 2 views
0

У меня есть два вопроса о наборах.Python 3.41 Набор

1. Так как я читал наборы неупорядочен, но когда я начал экспериментировать с ними, я узнал, что на самом деле есть какая-то вещь для заказа.

Как вы можете видеть, что нет ничего особенного в этом наборе:

>>> v_set ={88,11,1,33,21,3,7,55,37,8} 
>>> v_set 
{33, 1, 3, 37, 7, 8, 11, 21, 55, 88} 

Но это одна другая:

>>> g_set={7,5,11,1,4,13,55,12,2,3,6,20,9,10} 
>>> g_set 
{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 20, 55} 

Я думаю, это потому, что на этот раз я записал более тесные номера , и стало иметь смысл установить эти числа по возрастающей последовательности ...?

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

Как вы можете видеть:

>>> v_set 
{33, 1, 3, 37, 7, 8, 11, 21, 55, 88} 
>>> v_set.pop() 
33 
>>> v_set.pop() 
1 
>>> v_set.pop() 
3 
>>> v_set.pop() 
37 
>>> v_set.pop() 
7 
>>> v_set.pop() 
8 
>>> v_set.pop() 
11 
>>> v_set.pop() 
21 
>>> v_set.pop() 
55 

Так это на самом деле совершенно произвольно?

+0

Пожалуйста, оставляйте свои сообщения только на один вопрос *; ваша первая проблема - дубликат [Почему порядок в словарях Python произволен?] (http://stackoverflow.com/q/15479928) (наборы - это просто словари с просто ключами и без значений). –

+0

Порядок '.pop()' как «произвольный» как порядок итерации набора; для Python мало смысла «рандомизировать» это. –

ответ

0

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

In [4]: class Bad: 
    ...:  def __init__(self, val, hash_val): 
    ...:   self.val = val 
    ...:   self.hash_val = hash_val 
    ...:  def __str__(self): 
    ...:   return 'Bad({0.val}, {0.hash_val})'.format(self) 
    ...:  __repr__ = __str__ 
    ...:  def __eq__(self, other): 
    ...:   return self.val == other.val 
    ...:  def __hash__(self): 
    ...:   return self.hash_val 

In [5]: b1 = Bad(1, 1) 
    ...: b2 = Bad(2, 1) 
    ...: b3 = Bad(3, 2) 

In [6]: {b1, b2, b3} 
Out[6]: {Bad(2, 1), Bad(3, 2), Bad(1, 1)} 

In [7]: {b2, b1, b3} 
Out[7]: {Bad(1, 1), Bad(3, 2), Bad(2, 1)} 

Как вы можете видеть в Out[6] первый элемент Bad(2, 1), а последний Bad(1, 1) в Out[7] первый является Bad(1, 1), а последний Bad(2, 1).

Если бы не было никаких столкновений:

In [8]: b1 = Bad(1, 1) 
    ...: b2 = Bad(2, 2) 
    ...: b3 = Bad(3, 3) 

In [9]: {b1, b2, b3} 
Out[9]: {Bad(1, 1), Bad(2, 2), Bad(3, 3)} 

In [10]: {b2, b1, b3} 
Out[10]: {Bad(1, 1), Bad(2, 2), Bad(3, 3)} 

примечания как порядок не изменился. (Ну, хэш использует модуль n, поэтому возможны столкновения, даже если хеши разные, в зависимости от размера базовой таблицы).

Иными словами, значений недостаточно для определения порядка элементов set, даже если вы знаете, как они реализованы. Вы также должны знать порядок вставки.

В целом set с делают имеет четко определенный порядок внутри один проход интерпретатора (из-за randominzation в python3.3 +), однако , который порядка используются зависит от вставок, выполненных (как значение и порядок их выполнения) и произвольно, то есть в python3.5 они могут изменить порядок без уведомления, поэтому вы не можете положиться на него.

Они могут действительно рандомизировать выходы, но это просто добавит накладные расходы без какой-либо выгоды.

+0

Большое спасибо за объяснение этого! –

0

Да, заказ произвольный, по определению. Даже если элементы, хранящиеся в отсортированном порядке, все равно будут произвольными. «Произвольное» означает, что Python не обещает упорядочить данные каким-либо определенным образом. Поскольку память является линейной, она должна использовать порядка, но вы никогда не должны полагаться на этот заказ, потому что он может быть изменен без предварительного уведомления. (Фактически, в последних версиях Python порядок позиций в set равен partially randomized.)

Ваш второй пример показывает, что порядок печати такой же, как и порядок выскакивания. Это имеет смысл: repr перемещает элементы в том порядке, в котором они хранятся в памяти, и pop, по-видимому, возвращает первый элемент в соответствии с тем же заказом. Опять же, вы не можете положиться на это: это деталь реализации, и если разработчики Python выяснят более быстрый способ сделать pop, они могут разбить любой код, который опирается на заказ set.

Если вы хотите знать, как это работает, прочитайте хэш-таблицы.

+0

Действительно, как ваш ответ, спасибо за помощь! –

0

Это не совсем произвольно. Но это не имеет значения.

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

То же самое касается pop(). Весьма вероятно, что конкретная реализация используемого вами питона имеет логику, которая приведет к явно детерминированным результатам. Однако ваш код может использоваться с интерпретатором python, который использует другую реализацию. A random element - единственная гарантия, которую вы получаете от реализации.

Подводя итог, документация дает вам набор гарантий, согласно которым будет выполняться любая совместимая реализация python. Дополнительные эффекты, которые вы наблюдаете, являются деталями реализации и могут быть изменены в любое время.

+0

Спасибо за помощь! –