Каков наилучший способ организовать группу групп в Obj-c? - PullRequest
1 голос
/ 07 декабря 2009

У меня необычная проблема, когда у меня есть список фруктов (яблоко, апельсин, банан, виноград и т. Д. И т. Д.). Они могут быть организованы в небольшие группы, например:

Group 1: apple, green_apple, pineapple
Group 2: grapes, banana, strawberries, apple
Group 3: orange, grapes, green_apple

Каждая группа затем ассоциируется с ценой. Итак, группа 1-> 9,99, группа 2-> 15,99 и т. Д.

А потом, когда дан список, их необходимо сопоставить с существующими группами, и, если ни одна не была найдена, создать ее. Если таковой существует, верните цену.

Каков наилучший способ сделать это? По сути, ассоциация должна быть NSDictionary, но ключ, похоже, должен быть массивом. Проблема в том, как мне построить ключ, если дать какой-то ввод? Я должен прибегнуть к тому, чтобы все было в алфавитном порядке, чтобы ключи были последовательными? Но тогда этот подход не был бы слишком хорош, когда имена включают символы ($ apple и т. Д.).

Каким будет ваш подход?

Ответы [ 3 ]

3 голосов
/ 07 декабря 2009

Используйте NSSet вместо NSArray (наборы представляют собой неупорядоченные списки, и, похоже, это то, что вы получили здесь). Однако я не уверен, что NSDictionary будет использовать метод [NSSet isEqualToSet:] (или как его там) вместо равенства указателей при определении ключей, поэтому вам, возможно, придется реализовать собственный метод проверки ключей.

1 голос
/ 07 декабря 2009

Похоже, вы можете использовать NSSet в качестве ключа к NSDictionary:

NSMutableDictionary * dict = [NSMutableDictionary dictionary];

NSSet * set;
set = [NSSet setWithObjects:@"a", @"b", @"c", @"d", nil];
[dict setObject:@"1" forKey:set];

set = [NSSet setWithObjects:@"b", @"c", @"d", @"e", nil];
[dict setObject:@"2" forKey:set];

id key;
NSEnumerator * enumerator = [dict keyEnumerator];
while ((key = [enumerator nextObject]))
    NSLog(@"%@ : %@", key, [dict objectForKey:key]);

set = [NSSet setWithObjects:@"c", @"b", @"e", @"d", nil];
NSString * value = [dict objectForKey:set];
NSLog(@"set: %@ : key: %@", set, value);

Выходы:

2009-12-08 15:42:17.885 x[4989] (d, e, b, c) : 2
2009-12-08 15:42:17.887 x[4989] (d, a, b, c) : 1
2009-12-08 15:42:17.887 x[4989] set: (d, e, b, c) : key: 2

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

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

Если это вы возвращаете цену (ключ), если это не так, вы можете вставить его с ценой, основные части:

@interface ShoppingList : NSObject
{
    NSMutableDictionary * shoppingList;
}

- (void)setList:(NSSet*)aList
       forPrice:(double)aPrice
{
    [shoppingList setObject:aList forKey:[NSNumber numberWithDouble:aPrice]];
}

- (double)priceForList:(NSSet*)aList
{
    id key;
    NSEnumerator * enumerator = [shoppingList keyEnumerator];
    while ((key = [enumerator nextObject]))
    {
        NSSet * list = [shoppingList objectForKey:key];

        if ([aList isEqualToSet:list])
        {
            return [(NSNumber*)key doubleValue];
        }
    }

    return 0.0;
}

{
    ShoppingList * shoppingList = [[ShoppingList alloc] init];

    NSSet * list;
    double price = 0.0;

    list =
      [NSSet setWithObjects:@"apple",@"green_apple",@"pineapple",nil];
    [shoppingList setList:list forPrice:9.99];

    list =
      [NSSet setWithObjects:@"grapes",@"banana",@"strawberries",@"apple",nil];
    [shoppingList setList:list forPrice:15.99];

    list =
     [NSSet setWithObjects:@"orange",@"grapes",@"green_apple",nil];
    [shoppingList setList:list forPrice:7.50];

    // searching for this
    list =
      [NSSet setWithObjects:@"grapes",@"banana",@"strawberries",@"apple",nil];

    price = [shoppingList priceForList:list];
    if (price != 0.0)
    { 
        NSLog(@"price: %.2f, for pricelist: %@", price, list);
    }
    else
    {
        NSLog(@"shopping list not found: %@", list);
        [shoppingList setList:list forPrice:15.99];
    }
}
0 голосов
/ 08 декабря 2009

Вы можете использовать для этого простое решение CoreData, и в долгосрочной перспективе оно, вероятно, будет самым простым. Для вашего сценария вы можете создать две сущности, скажем, Item и PriceGroup. Сущность Item может иметь атрибут name и отношение priceGroup к одному. Сущность PriceGroup может иметь атрибут description (хотя в вашем сценарии это даже не нужно), атрибут price и отношение ко-многим items. Предполагая, что вы настроили эти две простые сущности и получили контекст, вы можете легко создать свои ассоциации, например, в коде:

- (void)createGroup:(NSNumber*)price withProducts:(NSSet*)productNames
{
  // assume context exists and was retrieved from somewhere
  NSManagedObject* priceGroup = [NSEntityDescription insertNewObjectForEntityForName:@"PriceGroup" inManagedObjectContext:context];
  [priceGroup setValue:price forKey:@"price"];

  for( NSString* productName in productNames ) {
    NSManagedObject* product = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:context];
    [product setValue:productName forKey:@"name"];
    [product setValue:priceGroup forKey:@"priceGroup"];
  }
}

Теперь все ваши продукты будут связаны с вашей ценовой группой в контексте вашего управляемого объекта. Это означает, что вы можете выполнять любые запросы к ним, легко сортировать их и т. Д.

В качестве другого примера, вот как вы можете получить все предметы, чья групповая цена превышает $ 9,99, но не в какой-то конкретной группе (скажем, в группе цен продажи $ 15,99):

- (NSSet*)itemsAsDescribed
{
  // Get this from somewhere
  NSManagedObjectContext* context = /* get this or set this */
  NSManagedObject* exclusionGroup = /* get this or set this */
  NSFetchRequest* request = [[[NSFetchRequest alloc] init] autorelease];
  NSPredicate* predicate = [NSPredicate predicateWithFormat:@"priceGroup.price >= 9.99 AND NOT SELF in %@", [exclusionGroup valueForKey:@"items"]];
  [request setEntity:[NSEntityDescription entityForName:@"Item" inManagedObjectContext:context]];
  [request setPredicate:predicate];
  NSError* error = nil;
  NSSet* results = nil;
  NSArray* array = [context executeFetchRequest:request error:&error];
  if( !array ) {
    // handle the error
  } else {
    results = [NSSet setWithArray:array];
  }
  return results;
}

В этом случае, поскольку не существует отношений «многие ко многим», иметь набор не нужно, однако, если вы изменили его в будущем, чтобы товар мог быть в нескольких группах (например, обычная ценовая группа и группа продажной цены), это необходимо для того, чтобы вы не получили повторяющиеся элементы в своем результате.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...