Синтаксис подзапроса NSPredicate - PullRequest
5 голосов
/ 09 марта 2012

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

NSPredicate *lookupPredicate = [NSPredicate predicateWithFormat:
             @"row_values.property_id == %@ AND row_values.property_value == %@",
               @"47cc67093475061e01000540", @"Male"];

[dataRows filterUsingPredicate:lookupPredicate];

Это не возвращает никаких значений. Я пробовал различные формы ЛЮБОГО, но я не могу найти ничего, что он будет анализировать. Опять же, цель состоит в том, чтобы сохранить только те словари внешних массивов, где предикат для ЛЮБОГО содержимого словаря внутреннего массива является истинным. Я вижу, как я жевал день, чтобы выяснить заклинание, чтобы сделать эту работу ... какие-нибудь идеи?

dataRows:
(
 {
    row = 1;
    "row_values" =     (
            {
              "property_id" = 47cc67093475061e01000542;
              "property_value" = "Mr.";
            },
            {
               "property_id" = 47cc67093475061e01000540;
               "property_value" = Male;
            }
     );
 },
 {
    row = 2;
    "row_values" =     (
           {
             "property_id" = 47cc67093475061e01000542;
             "property_value" = "Ms.";
           },
 ...
   }
}

Ответы [ 2 ]

21 голосов
/ 09 марта 2012

Человек, "недружелюбный" - преуменьшение этого массива!

ОК, думаю, я понял это:

NSArray *dataRows = @[
                      @{ @"row" : @"1",
                         @"row_values" : @[
                                           @{ @"property_id" : @"47cc67093475061e01000542", 
                                              @"property_value" : @"Mr." },
                                           @{ @"property_id" : @"47cc67093475061e01000540", 
                                              @"property_value" : @"Male" }
                                          ]
                       },
                      @{ @"row" : @"2",
                         @"row_values" : @[
                                           @{ @"property_id" : @"47cc67093475061e01000542", 
                                              @"property_value" : @"Ms." },
                                           @{ @"property_id" : @"47cc67093475061e01000540", 
                                              @"property_value" : @"Female" }
                                          ]
                       }
                     ];

NSPredicate *p = [NSPredicate predicateWithFormat:@"SUBQUERY(row_values, $rv, $rv.property_id = %@ AND $rv.property_value = %@).@count > 0", @"47cc67093475061e01000540", @"Male"];

NSArray *filtered = [dataRows filteredArrayUsingPredicate:p];

Итак, давайте посмотрим, что делает этот предикат.

  1. Начните с самого внешнего уровня:

    SUBQUERY([stuff]).@count > 0
    

    A SUBQUERY возвращает массив объектов. Мы собираемся запустить этот SUBQUERY для каждого NSDictionary в массиве dataRows, и мы хотим объединить все словари, где SUBQUERY в этом словаре возвращает что-то . Итак, мы запускаем SUBQUERY, а затем (так как он возвращает коллекцию), спрашиваем его, сколько элементов было в нем (.@count) и проверяем, больше ли это 0. Если это так, то словарь верхнего уровня будет в конечном фильтрованном массиве.

  2. Копать в SUBQUERY:

    SUBQUERY(row_values, $rv, $rv.property_id = %@ AND $rv.property_value = %@)
    

    Для каждого SUBQUERY есть три параметра: путь ключа, переменная и предикат. Ключевой путь - это свойство объекта, который мы собираемся повторять. Поскольку SUBQUERY оценивается в большинстве внешних словарей, мы собираемся запросить @"row_values" этого словаря и получить массив. Затем SUBQUERY будет перебирать элементы в коллекции row_values.

    Переменная - это то, что мы будем называть каждым элементом в коллекции. В этом случае это просто будет $rv (сокращение от «значение строки»). В нашем случае каждый $rv будет NSDictionary, так как "свойство" row_values является массивом словарей.

    Наконец, предикат будет выполнен с заменой $rv для каждого словаря по очереди. В этом случае мы хотим посмотреть, есть ли в словаре определенный property_id и определенный property_value. Если он делает , он будет объединен в новый массив , и это будет массив, который будет возвращен из SUBQUERY.

    Другими словами, SUBQUERY собирается построить массив всех значений row_values, которые имеют property_id и property_value того, что мы ищем.

И, наконец, когда я запускаю этот код, я получаю:

(
        {
        row = 1;
        "row_values" =         (
                        {
                "property_id" = 47cc67093475061e01000542;
                "property_value" = "Mr.";
            },
                        {
                "property_id" = 47cc67093475061e01000540;
                "property_value" = Male;
            }
        );
    }
)
0 голосов
/ 07 августа 2016

Документация Apple SUBQUERY разбросана по нескольким местам.

Формат строки для выражения подзапроса:

SUBQUERY(collection_expression, variable_expression, predicate);

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

Для получения дополнительной информации и примеров см. мой ответ на аналогичный вопрос о документации по синтаксису SUBQUERY .

...