Другой необычный подход, который работает для гетеро- и однородных списков целых чисел:
def unusual_flatten(some_list: list) -> list:
cleaned_list = str(some_list).replace(("["), "").replace("]", "").split(",")
return [int(item) for item in cleaned_list]
Применение в списке примеров ...
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9], 10]
unusual_flatten(l)
Результат:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
В принципе, дисперсия применяется, когда CLR может гарантировать, что ей не нужно делать какие-либо репрезентативные изменения к значениям. Все ссылки одинаковы, поэтому вы можете использовать IEnumerable<string>
как IEnumerable<object>
без каких-либо изменений в представлении; сам собственный код не обязательно должен знать, что вы делаете со значениями, если инфраструктура гарантировала, что он определенно будет действительным.
Для типов значений, которые не work - для обработки IEnumerable<int>
как IEnumerable<object>
, код, использующий последовательность, должен был бы знать, следует ли выполнять преобразование бокса или нет.
Возможно, вы захотите прочитать блог Эрика Липперта пост по представлению и идентичности для более подробной информации по этой теме в целом.
EDIT: перечитав блог в блоге Эрика, это как минимум примерно тождество как представление, хотя эти два связаны. В частности:
Вот почему ковариантные и контравариантные преобразования интерфейса и типов делегатов требуют, чтобы все переменные аргументы типа были ссылочными типами. Чтобы гарантировать, что вариантное преобразование ссылок всегда сохраняется с сохранением идентичности, все преобразования, связанные с аргументами типа, также должны сохраняться в идентичности. Самый простой способ гарантировать, что все нетривиальные преобразования в аргументах типа сохраняют сохранение идентичности, - это ограничение их ссылок на ссылки.
blockquote>
Я думаю, что все начинается с определения LSP
(Принцип замещения Лискова), который climes:
, если q (x) - свойство, доказуемое об объектах x типа T, то q ( y) должно быть истинным для объектов y типа S, где S является подтипом T.
blockquote>Но типы значений, например
int
, не могут быть замененыobject
вC#
. Доказательство очень просто:int myInt = new int(); object obj1 = myInt ; object obj2 = myInt ; return ReferenceEquals(obj1, obj2);
Это возвращает
false
, даже если мы назначим ту же «ссылку» на объект.
Он доходит до детали реализации: типы значений реализуются по-разному для ссылочных типов.
Если вы принудительно применяете типы значений как ссылочные типы (то есть оставьте их, например, обратившись к ним через интерфейс), вы можете получить дисперсию.
Самый простой способ увидеть разницу - просто рассмотреть Array
: массив типов значений объединяется в память смежно (напрямую), где в качестве массива В ссылочных типах всегда имеется ссылка (указатель) в памяти; объекты, на которые указываются, выделены отдельно.
Другая (связанная) проблема (*) заключается в том, что (почти) все типы ссылок имеют одинаковое представление для целей дисперсии, и много кода не нужно знать о разница между типами, поэтому возможна совпадение и противоречие (и легко реализуются - часто просто за счет исключения дополнительной проверки типов).
(*) Это может рассматриваться как одна и та же проблема. .
Возможно, вам легче понять, если вы думаете о базовом представлении (хотя это действительно детализация реализации). Вот набор строк:
IEnumerable<string> strings = new[] { "A", "B", "C" };
Вы можете думать о том, что strings
имеет следующее представление:
[0] : string reference -> "A" [1] : string reference -> "B" [2] : string reference -> "C"
Это набор из трех элементов, каждый являясь ссылкой на строку. Вы можете передать это в коллекцию объектов:
IEnumerable<object> objects = (IEnumerable<object>) strings;
В основном это то же представление, за исключением того, что ссылки являются ссылками на объекты:
[0] : object reference -> "A" [1] : object reference -> "B" [2] : object reference -> "C"
Представление такое же. Ссылки рассматриваются только по-разному; вы больше не можете получить доступ к свойству string.Length
, но вы все равно можете вызвать object.GetHashCode()
. Сравните это с коллекцией ints:
IEnumerable<int> ints = new[] { 1, 2, 3 };
[0] : int = 1 [1] : int = 2 [2] : int = 3
Чтобы преобразовать это в IEnumerable<object>
, данные должны быть преобразованы путем бокса ints:
[0] : object reference -> 1 [1] : object reference -> 2 [2] : object reference -> 3
Это преобразование требует больше, чем литье.