Enumerable. Any Метод
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Проверяет существование хотя бы одного элемента в последовательности.
Перегрузки
Проверяет, содержит ли последовательность какие-либо элементы.
Проверяет, удовлетворяет ли какой-либо элемент последовательности заданному условию.
Any(IEnumerable)
Проверяет, содержит ли последовательность какие-либо элементы.
public: generic [System::Runtime::CompilerServices::Extension] static bool Any(System::Collections::Generic::IEnumerable ^ source);
public static bool Any (this System.Collections.Generic.IEnumerable source);
static member Any : seq -> bool
Public Function Any(Of TSource) (source As IEnumerable(Of TSource)) As Boolean
Параметры типа
Тип элементов source .
Параметры
Возвращаемое значение
true , если исходная последовательность содержит какие-либо элементы, в противном случае — false .
Исключения
source имеет значение null .
Примеры
В следующем примере кода показано, как с помощью Any определить, содержит ли последовательность какие-либо элементы.
List numbers = new List < 1, 2 >; bool hasElements = numbers.Any(); Console.WriteLine("The list empty.", hasElements ? "is not" : "is"); // This code produces the following output: // // The list is not empty.
' Create a list of Integers. Dim numbers As New List(Of Integer)(New Integer() ) ' Determine if the list contains any items. Dim hasElements As Boolean = numbers.Any() ' Display the output. Dim text As String = IIf(hasElements, "not ", "") Console.WriteLine($"The list is empty.") ' This code produces the following output: ' ' The list is not empty.
Логическое значение, возвращаемое методом Any(IEnumerable) , обычно используется в предикате where предложения ( Where предложение в Visual Basic) или при прямом вызове Where(IEnumerable, Func) метода . В следующем примере показано использование Any метода .
class Pet < public string Name < get; set; >public int Age < get; set; >> class Person < public string LastName < get; set; >public Pet[] Pets < get; set; >> public static void AnyEx2() < Listpeople = new List < new Person < LastName = "Haas", Pets = new Pet[] < new Pet < Name="Barley", Age=10 >, new Pet < Name="Boots", Age=14 >, new Pet < Name="Whiskers", Age=6 >>>, new Person < LastName = "Fakhouri", Pets = new Pet[] < new Pet < Name = "Snowball", Age = 1>>>, new Person < LastName = "Antebi", Pets = new Pet[] < >>, new Person < LastName = "Philips", Pets = new Pet[] < new Pet < Name = "Sweetie", Age = 2>, new Pet < Name = "Rover", Age = 13>> > >; // Determine which people have a non-empty Pet array. IEnumerable names = from person in people where person.Pets.Any() select person.LastName; foreach (string name in names) < Console.WriteLine(name); >/* This code produces the following output: Haas Fakhouri Philips */ >
Structure Pet Public Name As String Public Age As Integer End Structure Structure Person Public LastName As String Public Pets() As Pet End Structure Sub AnyEx2() Dim people As New List(Of Person)(New Person() _ , New Pet With , New Pet With >>, New Person With >>, New Person With >, New Person With , New Pet With >>>) ' Determine which people have a non-empty Pet array. Dim names = From person In people Where person.Pets.Any() Select person.LastName For Each name As String In names Console.WriteLine(name) Next ' This code produces the following output: ' ' Haas ' Fakhouri ' Philips End Sub
Комментарии
Этот метод не возвращает ни один элемент коллекции. Вместо этого он определяет, содержит ли коллекция какие-либо элементы.
Перечисление source останавливается, как только можно определить результат.
В синтаксисе Aggregate Into Any() выражения запроса Visual Basic предложение преобразуется в вызов Any.
Как работать с алгоритмом any_of из стандартной библиотеки?
Ну, семантика — «существует хотя бы один такой элемент, что». А синтаксис — передача диапазона (где проверяем существование элемента) и предиката (какого именно элемента существование).
Например, проверка, есть ли среди чисел в векторе четное:
void even_check(const std::vector& v) < if (std::any_of(v.cbegin(), v.cend(), [](int i)< return i % 2 == 0; >)) < std::cout else < std::cout > int main() < std::vectorv; even_check(v); v.push_back(10); even_check(v); >
Ну, и на всякий случай (вдруг вы это хотели услышать): диапазон передается как два итератора. Синтаксического сахара в духе цикла по диапазону нет. Можно написать свой вариант для всего контейнера, типа
template bool any_in(const Container c, Pred p) < return any_of(cbegin(c),cend(c),p); >void even_check(std::vector& v) < if (any_in(v, [](int i)< return i % 2 == 0; >)) < std::cout else < std::cout >
Секция JOIN
JOIN создаёт новую таблицу путем объединения столбцов из одной или нескольких таблиц с использованием общих для каждой из них значений. Это обычная операция в базах данных с поддержкой SQL, которая соответствует join из реляционной алгебры. Частный случай соединения одной таблицы часто называют self-join.
Синтаксис
SELECT expr_list> FROM left_table> [GLOBAL] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI|ANY|ASOF] JOIN right_table> (ON expr_list>)|(USING column_list>) ...
Выражения из секции ON и столбцы из секции USING называются «ключами соединения». Если не указано иное, при присоединение создаётся Декартово произведение из строк с совпадающими значениями ключей соединения, что может привести к получению результатов с гораздо большим количеством строк, чем исходные таблицы.
Поддерживаемые типы соединения
Все типы из стандартного SQL JOIN поддерживаются:
- INNER JOIN , возвращаются только совпадающие строки.
- LEFT OUTER JOIN , не совпадающие строки из левой таблицы возвращаются в дополнение к совпадающим строкам.
- RIGHT OUTER JOIN , не совпадающие строки из правой таблицы возвращаются в дополнение к совпадающим строкам.
- FULL OUTER JOIN , не совпадающие строки из обеих таблиц возвращаются в дополнение к совпадающим строкам.
- CROSS JOIN , производит декартово произведение таблиц целиком, ключи соединения не указываются.
Без указания типа JOIN подразумевается INNER . Ключевое слово OUTER можно опускать. Альтернативным синтаксисом для CROSS JOIN является указание нескольких таблиц, разделённых запятыми, в секции FROM.
Дополнительные типы соединений, доступные в ClickHouse:
- LEFT SEMI JOIN и RIGHT SEMI JOIN , белый список по ключам соединения, не производит декартово произведение.
- LEFT ANTI JOIN и RIGHT ANTI JOIN , черный список по ключам соединения, не производит декартово произведение.
- LEFT ANY JOIN , RIGHT ANY JOIN и INNER ANY JOIN , Частично (для противоположных сторон LEFT и RIGHT ) или полностью (для INNER и FULL ) отключает декартово произведение для стандартных видов JOIN .
- ASOF JOIN и LEFT ASOF JOIN , Для соединения последовательностей по нечеткому совпадению. Использование ASOF JOIN описано ниже.
Примечание
Если настройка join_algorithm установлена в значение partial_merge , то для RIGHT JOIN и FULL JOIN поддерживается только уровень строгости ALL ( SEMI , ANTI , ANY и ASOF не поддерживаются).
Настройки
Значение строгости по умолчанию может быть переопределено с помощью настройки join_default_strictness.
Поведение сервера ClickHouse для операций ANY JOIN зависит от параметра any_join_distinct_right_table_keys.
См. также
- join_algorithm
- join_any_take_last_row
- join_use_nulls
- partial_merge_join_optimizations
- partial_merge_join_rows_in_right_blocks
- join_on_disk_max_files_to_merge
- any_join_distinct_right_table_keys
Условия в секции ON
Секция ON может содержать несколько условий, связанных операторами AND и OR . Условия, задающие ключи соединения, должны содержать столбцы левой и правой таблицы и должны использовать оператор равенства. Прочие условия могут использовать другие логические операторы, но в отдельном условии могут использоваться столбцы либо только левой, либо только правой таблицы.
Строки объединяются только тогда, когда всё составное условие выполнено. Если оно не выполнено, то строки могут попасть в результат в зависимости от типа JOIN . Обратите внимание, что если то же самое условие поместить в секцию WHERE , то строки, для которых оно не выполняется, никогда не попаду в результат.
Оператор OR внутри секции ON работает, используя алгоритм хеш-соединения — на каждый аргумент OR с ключами соединений для JOIN создается отдельная хеш-таблица, поэтому потребление памяти и время выполнения запроса растет линейно при увеличении количества выражений OR секции ON .
Примечание
Если в условии использованы столбцы из разных таблиц, то пока поддерживается только оператор равенства ( = ).
Пример
Рассмотрим table_1 и table_2 :
┌─Id─┬─name─┐ ┌─Id─┬─text───────────┬─scores─┐ │ 1 │ A │ │ 1 │ Text A │ 10 │ │ 2 │ B │ │ 1 │ Another text A │ 12 │ │ 3 │ C │ │ 2 │ Text B │ 15 │ └────┴──────┘ └────┴────────────────┴────────┘
Запрос с одним условием, задающим ключ соединения, и дополнительным условием для table_2 :
SELECT name, text FROM table_1 LEFT OUTER JOIN table_2 ON table_1.Id = table_2.Id AND startsWith(table_2.text, 'Text');
Обратите внимание, что результат содержит строку с именем C и пустым текстом. Строка включена в результат, потому что использован тип соединения OUTER .
┌─name─┬─text───┐ │ A │ Text A │ │ B │ Text B │ │ C │ │ └──────┴────────┘
Запрос с типом соединения INNER и несколькими условиями:
SELECT name, text, scores FROM table_1 INNER JOIN table_2 ON table_1.Id = table_2.Id AND table_2.scores > 10 AND startsWith(table_2.text, 'Text');
┌─name─┬─text───┬─scores─┐ │ B │ Text B │ 15 │ └──────┴────────┴────────┘
Запрос с типом соединения INNER и условием с оператором OR :
CREATE TABLE t1 (`a` Int64, `b` Int64) ENGINE = MergeTree() ORDER BY a; CREATE TABLE t2 (`key` Int32, `val` Int64) ENGINE = MergeTree() ORDER BY key; INSERT INTO t1 SELECT number as a, -a as b from numbers(5); INSERT INTO t2 SELECT if(number % 2 == 0, toInt64(number), -number) as key, number as val from numbers(5); SELECT a, b, val FROM t1 INNER JOIN t2 ON t1.a = t2.key OR t1.b = t2.key;
┌─a─┬──b─┬─val─┐ │ 0 │ 0 │ 0 │ │ 1 │ -1 │ 1 │ │ 2 │ -2 │ 2 │ │ 3 │ -3 │ 3 │ │ 4 │ -4 │ 4 │ └───┴────┴─────┘
Запрос с типом соединения INNER и условиями с операторами OR и AND :
SELECT a, b, val FROM t1 INNER JOIN t2 ON t1.a = t2.key OR t1.b = t2.key AND t2.val > 3;
┌─a─┬──b─┬─val─┐ │ 0 │ 0 │ 0 │ │ 2 │ -2 │ 2 │ │ 4 │ -4 │ 4 │ └───┴────┴─────┘
Использование ASOF JOIN
ASOF JOIN применим в том случае, когда необходимо объединять записи, которые не имеют точного совпадения.
Для работы алгоритма необходим специальный столбец в таблицах. Этот столбец:
- Должен содержать упорядоченную последовательность.
- Может быть одного из следующих типов: Int, UInt, Float, Date, DateTime, Decimal.
- Не может быть единственным столбцом в секции JOIN .
Синтаксис ASOF JOIN . ON :
SELECT expressions_list FROM table_1 ASOF LEFT JOIN table_2 ON equi_cond AND closest_match_cond
Можно использовать произвольное количество условий равенства и одно условие на ближайшее совпадение. Например, SELECT count() FROM table_1 ASOF LEFT JOIN table_2 ON table_1.a == table_2.b AND table_2.t
Условия, поддержанные для проверки на ближайшее совпадение: > , >= , < ,
Синтаксис ASOF JOIN . USING :
SELECT expressions_list FROM table_1 ASOF JOIN table_2 USING (equi_column1, ... equi_columnN, asof_column)
Для слияния по равенству ASOF JOIN использует equi_columnX , а для слияния по ближайшему совпадению использует asof_column с условием table_1.asof_column >= table_2.asof_column . Столбец asof_column должен быть последним в секции USING .
Например, рассмотрим следующие таблицы:
table_1 table_2 event | ev_time | user_id event | ev_time | user_id ----------|---------|---------- ----------|---------|---------- . . event_1_1 | 12:00 | 42 event_2_1 | 11:59 | 42 . event_2_2 | 12:30 | 42 event_1_2 | 13:00 | 42 event_2_3 | 13:00 | 42 . .
ASOF JOIN принимает метку времени пользовательского события из table_1 и находит такое событие в table_2 метка времени которого наиболее близка к метке времени события из table_1 в соответствии с условием на ближайшее совпадение. При этом столбец user_id используется для объединения по равенству, а столбец ev_time для объединения по ближайшему совпадению. В нашем примере event_1_1 может быть объединено с event_2_1 , event_1_2 может быть объединено с event_2_3 , а event_2_2 не объединяется.
Примечание
ASOF JOIN не поддержан для движка таблиц Join.
Чтобы задать значение строгости по умолчанию, используйте сессионный параметр join_default_strictness.
Распределённый JOIN
Есть два пути для выполнения соединения с участием распределённых таблиц:
- При использовании обычного JOIN , запрос отправляется на удалённые серверы. На каждом из них выполняются подзапросы для формирования «правой» таблицы, и с этой таблицей выполняется соединение. То есть, «правая» таблица формируется на каждом сервере отдельно.
- При использовании GLOBAL . JOIN , сначала сервер-инициатор запроса запускает подзапрос для вычисления правой таблицы. Эта временная таблица передаётся на каждый удалённый сервер, и на них выполняются запросы с использованием переданных временных данных.
Будьте аккуратны при использовании GLOBAL . За дополнительной информацией обращайтесь в раздел Распределенные подзапросы.
Неявные преобразования типов
Запросы INNER JOIN , LEFT JOIN , RIGHT JOIN и FULL JOIN поддерживают неявные преобразования типов для ключей соединения. Однако запрос не может быть выполнен, если не существует типа, к которому можно привести значения ключей с обеих сторон (например, нет типа, который бы одновременно вмещал в себя значения UInt64 и Int64 , или String и Int32 ).
Пример
Рассмотрим таблицу t_1 :
┌─a─┬─b─┬─toTypeName(a)─┬─toTypeName(b)─┐ │ 1 │ 1 │ UInt16 │ UInt8 │ │ 2 │ 2 │ UInt16 │ UInt8 │ └───┴───┴───────────────┴───────────────┘
┌──a─┬────b─┬─toTypeName(a)─┬─toTypeName(b)───┐ │ -1 │ 1 │ Int16 │ Nullable(Int64) │ │ 1 │ -1 │ Int16 │ Nullable(Int64) │ │ 1 │ 1 │ Int16 │ Nullable(Int64) │ └────┴──────┴───────────────┴─────────────────┘
SELECT a, b, toTypeName(a), toTypeName(b) FROM t_1 FULL JOIN t_2 USING (a, b);
┌──a─┬────b─┬─toTypeName(a)─┬─toTypeName(b)───┐ │ 1 │ 1 │ Int32 │ Nullable(Int64) │ │ 2 │ 2 │ Int32 │ Nullable(Int64) │ │ -1 │ 1 │ Int32 │ Nullable(Int64) │ │ 1 │ -1 │ Int32 │ Nullable(Int64) │ └────┴──────┴───────────────┴─────────────────┘
Рекомендации по использованию
Обработка пустых ячеек и NULL
При соединении таблиц могут появляться пустые ячейки. Настройка join_use_nulls определяет, как ClickHouse заполняет эти ячейки.
Если ключами JOIN выступают поля типа Nullable, то строки, где хотя бы один из ключей имеет значение NULL, не соединяются.
Синтаксис
Требуется, чтобы столбцы, указанные в USING , назывались одинаково в обоих подзапросах, а остальные столбцы — по-разному. Изменить имена столбцов в подзапросах можно с помощью синонимов.
В секции USING указывается один или несколько столбцов для соединения, что обозначает условие на равенство этих столбцов. Список столбцов задаётся без скобок. Более сложные условия соединения не поддерживаются.
Ограничения cинтаксиса
Для множественных секций JOIN в одном запросе SELECT :
- Получение всех столбцов через * возможно только при объединении таблиц, но не подзапросов.
- Секция PREWHERE недоступна.
Для секций ON , WHERE и GROUP BY :
- Нельзя использовать произвольные выражения в секциях ON , WHERE , и GROUP BY , однако можно определить выражение в секции SELECT и затем использовать его через алиас в других секциях.
Производительность
При запуске JOIN , отсутствует оптимизация порядка выполнения по отношению к другим стадиям запроса. Соединение (поиск в «правой» таблице) выполняется до фильтрации в WHERE и до агрегации. Чтобы явно задать порядок вычислений, рекомендуется выполнять JOIN подзапроса с подзапросом.
Каждый раз для выполнения запроса с одинаковым JOIN , подзапрос выполняется заново — результат не кэшируется. Это можно избежать, используя специальный движок таблиц Join, представляющий собой подготовленное множество для соединения, которое всегда находится в оперативке.
В некоторых случаях более эффективно использовать IN вместо JOIN .
Если JOIN необходим для соединения с таблицами измерений (dimension tables — сравнительно небольшие таблицы, которые содержат свойства измерений — например, имена для рекламных кампаний), то использование JOIN может быть не очень удобным из-за громоздкости синтаксиса, а также из-за того, что правая таблица читается заново при каждом запросе. Специально для таких случаев существует функциональность «Внешние словари», которую следует использовать вместо JOIN . Дополнительные сведения смотрите в разделе «Внешние словари».
Ограничения по памяти
По умолчанию ClickHouse использует алгоритм hash join. ClickHouse берет правую таблицу и создает для нее хеш-таблицу в оперативной памяти. При включённой настройке join_algorithm = ‘auto’ , после некоторого порога потребления памяти ClickHouse переходит к алгоритму merge join. Описание алгоритмов JOIN см. в настройке join_algorithm.
Если вы хотите ограничить потребление памяти во время выполнения операции JOIN , используйте настройки:
- max_rows_in_join — ограничивает количество строк в хеш-таблице.
- max_bytes_in_join — ограничивает размер хеш-таблицы.
По достижении любого из этих ограничений ClickHouse действует в соответствии с настройкой join_overflow_mode.
Примеры
SELECT CounterID, hits, visits FROM ( SELECT CounterID, count() AS hits FROM test.hits GROUP BY CounterID ) ANY LEFT JOIN ( SELECT CounterID, sum(Sign) AS visits FROM test.visits GROUP BY CounterID ) USING CounterID ORDER BY hits DESC LIMIT 10
┌─CounterID─┬───hits─┬─visits─┐ │ 1143050 │ 523264 │ 13665 │ │ 731962 │ 475698 │ 102716 │ │ 722545 │ 337212 │ 108187 │ │ 722889 │ 252197 │ 10547 │ │ 2237260 │ 196036 │ 9522 │ │ 23057320 │ 147211 │ 7689 │ │ 722818 │ 90109 │ 17847 │ │ 48221 │ 85379 │ 4652 │ │ 19762435 │ 77807 │ 7026 │ │ 722884 │ 77492 │ 11056 │ └───────────┴────────┴────────┘
Any и AnyObject в Swift. В чем их различие?
Довольно долгое время в своих проектах при написании когда я использовал тип Any, например при обработке JSON данных. Но также я знал что есть и второй тип — AnyObject. И недавно я задумался о разнице между этими двумя типами.
Согласно документации Apple:
- Any — может представлять экземпляр любого типа
- AnyObject — может представлять экземпляр любого класса
- Any используется для всех типов
- AnyObject — используется для типов Class
Для этого создадим массив с типом Any, и распечатаем его.
let anyArray: [Any] = ["Macbook", 1, 2] print(anyArray) Console: ["Macbook", 1, 2]
Как мы видим, Any позволяет работать с различными типами данных одновременно (String, Int).
Согласно документации, элементы (String и Int) в этом массиве являются структурами, которые являются типами значений, поэтому, теоретически, AnyObject не должен работать.
Чтобы проверить это, создадим идентичный массив, с типом AnyObject.
let anyObjectArray: [AnyObject] = ["Macbook", 1, 2]
Как и ожидалось, компилятор выдает нам ошибку о невозможности преобразовании типа «String/Int» к типу AnyObject
Ошибка компилятора
Cannot convert value of type «Int» to expected element type «AnyObject»
Cannot convert value of type «Int» to expected element type «AnyObject»
Cannot convert value of type «String» to expected element type «AnyObject»
Но давайте все таки попробуем привести три наших типа к AnyObject и распечатать результат.
let anyObjectArray: [AnyObject] = ["Macbook" as AnyObject, 1 as AnyObject, 2 as AnyObject] print(anyObjectArray) Console: [Macbook, 1, 2]
Ошибка компилятора исчезла. Как мы видим, строка Macbook явно выглядит как строка, но не имеет привычных кавычек как у типа String в Swift.
Попробуем распечатать массив с помощью цикла, чтобы проверить их фактический тип.
for item in anyObjectArray < if item is String < print("\(item) является типом String") >else if item is Int < print("\(item) является типом Int") >> Console: Macbook является типом String 1 является типом Int 2 является типом Int
Строка имеет тип String. Как было сказано раньше, строки в Swift являются структурами, а не типами классов. Значит, мы не должны иметь возможность использовать их как AnyObject.
Проведем еще пару экспериментов с нашим массивом. Попробуем проверить их на типы из Objective‑C: NSString и NSNumber.
for item in anyObjectArray < if item is NSString < print("\(item) является типом NSString") >else if item is NSNumber < print("\(item) является типом NSNumber") >> Console: Macbook является типом NSString 1 является типом NSNumber 2 является типом NSNumber
Так почему такое происходит?
Как часть своей совместимости с Objective‑C, Swift предлагает удобные и эффективные способы работы с платформами Cocoa.
Swift автоматически преобразует некоторые типы Objective‑C в типы Swift, а некоторые типы Swift в типы Objective‑C. Типы, которые можно конвертировать между Objective‑C и Swift, называются соединенными.
Другими словами, компилятор делает все возможное, чтобы быть гибким в обработке таких типов посредством автоматического преобразования и создания «мостов», в то же время предотвращая сбои приложения.
Когда же использовать AnyObject?
Как говорится в документации Apple, AnyObject может быть использован для работы с объектами, которые являются производными от Class, но не имеют общего корневого класса.
В Swift 3 тип id в Objective‑C теперь отображается на тип Any в Swift, который описывает значение любого типа, будь то класс, перечисление, структура или любой другой тип Swift. Это изменение делает API-интерфейсы Objective‑C более гибкими в Swift, поскольку определяемые Swift типы значений могут передаваться в Objective‑C API-интерфейсы и извлекаться как типы Swift, что устраняет необходимость в ручных «блочных» типах.
Таким образом, AnyObject желательно использовать когда вы хотите ограничить протокол, чтобы его можно было использовать лишь с классами, а Any в остальных случаях.
Apple добавляет:
Используйте Any и AnyObject только тогда, когда вам явно нужно поведение и возможности, которые они предоставляют. Всегда лучше быть точным в отношении типов, которые вы ожидаете использовать в своем коде.
- Разработка под iOS
- Objective C
- Swift