2012-03-09 5 views
5

У меня есть недружественный массив словарей, которые, в свою очередь, имеют массивы данных, и я пытаюсь отфильтровать внешний массив на основе любого внутреннего массива, передающего предикат. Я не могу создать NSPredicate для выполнения этой работы. Я начал с:Синтаксис подзапроса 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."; 
      }, 
... 
    } 
} 
+0

Возможный дубликат [Где найти документацию функции SUBQUERY для NSPredicate для основных данных?] (Http://stackoverflow.com/questions/3076618/where-to-find-the-documentation-of-the- subquery-feature-of-nspredicate-for-core) – Senseful

ответ

21

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

Хорошо, я думаю, что я понял это:

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 = %@)[email protected] > 0", @"47cc67093475061e01000540", @"Male"]; 

NSArray *filtered = [dataRows filteredArrayUsingPredicate:p]; 

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

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

    SUBQUERY([stuff])[email protected] > 0 
    

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

  2. Dig в к 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; 
      } 
     ); 
    } 
) 
+1

На самом деле я просто упростил структуру источника, чтобы использовать гораздо более простой предикат. Шутка ... спасибо тебе, Дэйв! Это отлично работает, и это имеет смысл. Я действительно ценю помощь и даю знать, нужна ли вам помощь по поводу значений RGB для черных или сколько гласных на английском языке - это то, что я могу обработать. – michael

+1

Удивительно, спасибо Дэйв! – flypig

0

подзапрос документация Apple, разбросаны по всему нескольких местах.

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

SUBQUERY(collection_expression, variable_expression, predicate);

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

Для получения более подробной информации и примеров см. my answer to a similar question about the documentation for SUBQUERY syntax.