Большой Условие для размещения элементов в массивах секций, лучше подойдет?- Цель-С - PullRequest
2 голосов
/ 26 января 2012

У меня есть этот кусок кода для помещения элементов из массива в соответствующий раздел в UITableView в зависимости от их начальной буквы:

//For each product in the appDelgates products
for (Product *product in appDelegate.m_Products){
    if ([product.category isEqualToString:productType]){

        //firstLetter is equal to the first letter of the products name
        NSString * l_FirstLetter = [product.name substringToIndex:1];
        //convert firstString to uppercase
        l_FirstLetter = [l_FirstLetter uppercaseString];

        //Check what letter firstString is equal to in the alphabet
        //Place in appropriate section
        //If none, place in "Other" category
        if ([l_FirstLetter isEqualToString:@"A"]) {
            [[m_AlphabetDictionary objectAtIndex:0] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"B"]) {
            [[m_AlphabetDictionary objectAtIndex:1] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"C"]) {
            [[m_AlphabetDictionary objectAtIndex:2] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"D"]) {
            [[m_AlphabetDictionary objectAtIndex:3] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"E"]) {
            [[m_AlphabetDictionary objectAtIndex:4] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"F"]) {
            [[m_AlphabetDictionary objectAtIndex:5] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"G"]) {
            [[m_AlphabetDictionary objectAtIndex:6] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"H"]) {
            [[m_AlphabetDictionary objectAtIndex:7] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"I"]) {
            [[m_AlphabetDictionary objectAtIndex:8] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"J"]) {
            [[m_AlphabetDictionary objectAtIndex:9] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"K"]) {
            [[m_AlphabetDictionary objectAtIndex:10] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"L"]) {
            [[m_AlphabetDictionary objectAtIndex:11] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"M"]) {
            [[m_AlphabetDictionary objectAtIndex:12] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"N"]) {
            [[m_AlphabetDictionary objectAtIndex:13] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"O"]) {
            [[m_AlphabetDictionary objectAtIndex:14] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"P"]) {
            [[m_AlphabetDictionary objectAtIndex:15] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"Q"]) {
            [[m_AlphabetDictionary objectAtIndex:16] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"R"]) {
            [[m_AlphabetDictionary objectAtIndex:17] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"S"]) {
            [[m_AlphabetDictionary objectAtIndex:18] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"T"]) {
            [[m_AlphabetDictionary objectAtIndex:19] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"U"]) {
            [[m_AlphabetDictionary objectAtIndex:20] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"V"]) {
            [[m_AlphabetDictionary objectAtIndex:21] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"W"]) {
            [[m_AlphabetDictionary objectAtIndex:22] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"X"]) {
            [[m_AlphabetDictionary objectAtIndex:23] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"Y"]) {
            [[m_AlphabetDictionary objectAtIndex:24] addObject:product];
        }
        else if ([l_FirstLetter isEqualToString:@"Z"]) {
            [[m_AlphabetDictionary objectAtIndex:25] addObject:product];
        }
        else {
            [[m_AlphabetDictionary objectAtIndex:26] addObject:product];
        }

    }
}

Есть ли лучший подход?

Спасибо

Джек

Ответы [ 5 ]

3 голосов
/ 26 января 2012

преобразуйте символ в целое число минус целое число символа "А"

и просто используйте [[m_AlphabetDictionary objectAtIndex:myInt] addObject:product];

и убедитесь, что вы используете только буквы.и если вы хотите поддерживать маленькие и большие буквы, вы должны вычесть символ 'a' из маленьких букв.

Существуют более сложные подходы, если вам нужно поддерживать локали и диакритические знаки в будущем, но это будетработать для наборов a… z и A… Z, определенных в OP:

Во-первых, многословная версия, которая документирует, как это работает:

static inline NSUInteger InsertionIndexForProductNamed(NSString * product) {
  assert(0 < product.length && "invalid argument");

  const int A = 'A';
  const int Z = 'Z';
  const int a = 'a';
  const int z = 'z';

  const unichar first = [product characterAtIndex:0];
  const bool isLowercaseAZ = a <= first && z >= first;
  const int uppercase = isLowercaseAZ ? (first + A - a) : first;
  const bool isUppercaseAZ = A <= uppercase && Z >= uppercase;

  if (isUppercaseAZ) {
    const int result = uppercase - A;
    return (NSUInteger)result;
  }
  else {
    /* not A-Z. place in 'other' */
    return 26;
  }
}

Теперь короткая версия, которая болеев соответствии с тем, что вы можете видеть в дикой природе:

static inline NSUInteger InsertionIndexForProductNamed(NSString* product) {
  assert(0 < product.length && "invalid argument");

  const unichar first = [product characterAtIndex:0];
  switch (first) {
    case 'A'...'Z' :
      return first - 'A';
    case 'a'...'z' :
      return first - 'a';
    default :
      return 26;
  }
}

Используется:

/* For each product in the appDelgates products */
for (Product * product in appDelegate.m_Products) {
  if ([product.category isEqualToString:productType]) {
    const NSUInteger idx = InsertionIndexForProductNamed(product.name);
    [[m_AlphabetDictionary objectAtIndex:idx] addObject:product];
  }
}

Наконец, короткая встроенная реализация может принять этоформа:

/* For each product in the appDelgates products */
for (Product * product in appDelegate.m_Products) {
  if ([product.category isEqualToString:productType]) {
    const NSUInteger insertionIndex;
    const unichar first = [product characterAtIndex:0];
    switch (first) {
      case 'A'...'Z' :
        insertionIndex = first - 'A';
        break;
      case 'a'...'z' :
        insertionIndex = first - 'a';
        break;
      default :
        insertionIndex = 26; // 26 is the index of the 'other' category
        break;
    }
    [[m_AlphabetDictionary objectAtIndex:insertionIndex] addObject:product];
  }
}

также обратите внимание на мой ObjC / блочный ответ

1 голос
/ 26 января 2012

Перемешивание с символами позволяет вам получать странные проблемы, когда вы добавляете объекты к индикаторам, которые находятся за пределами [0,25], что является большим нет-нет.Явно объявив свой словарь, вы можете избежать этого.

 bool added = NO;
 NSArray* theAlphabet = [NSArray arrayWithObjects:@"A",@"B",@"C" ... ,@"Z",nil];
 for(int i=0; i<26; i++){
     if ([l_FirstLetter isEqualToString:[theAlphabet objectAtIndex:i]]) {
        [[m_AlphabetDictionary objectAtIndex:i] addObject:product];
        added = YES;
     }
 }
 if(!added)
     [[m_AlphabetDictionary objectAtIndex:26] addObject:product];

Флаг added гарантирует, что объекты, первая буква которых не является буквой, добавляются в массив 26.

0 голосов
/ 27 января 2012

Рядом с моим другим ответом в стиле C (еще раз спасибо, @Justin) я хочу постулировать другой ответ.

На этот раз я использую только синтаксис target-c и блоки.

Создание массива слов:

NSString *text = @"Lorem ipsum dolor sit amet,..."; // Lorem ipsum with non-letter words
NSArray *words = [[[text stringByReplacingOccurrencesOfString:@"." withString:@""] 
                         stringByReplacingOccurrencesOfString:@"," withString:@""] 
                            componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

создание и заполнение словаря:

NSMutableDictionary *wordDict = [NSMutableDictionary dictionary];
[words performBlock:^(id element) {
    NSString *firstLetter = [[element substringToIndex:1] uppercaseString];
    if ([firstLetter isGreaterThanOrEqualTo:@"A"] && [firstLetter isLessThanOrEqualTo:@"Z"]){
        if (![[wordDict allKeys] containsObject:firstLetter]) {
            NSMutableArray *array = [NSMutableArray array];
            wordDict[firstLetter] = array;
        }

        [wordDict[firstLetter] addObject:element];
    } else {
        if (![[wordDict allKeys] containsObject:@"other"]) {
            NSMutableArray *array = [NSMutableArray array];
            wordDict[@"other"] = array;
        }
        [wordDict[@"other"] addObject:element];
    }
}];

NSLog(@"%@",wordDict);

Обратите внимание, что этот код использует метод категории в NSArray performBlock:. Этот метод не более чем применяет блок к каждому элементу в массиве. Его можно найти на github .

-(void)performBlock:(void (^)(id))block
{
    for(id element in self) {
        block(element);
    }
}

выход

{
    A =     (
        amet,
        aliquyam,
        At,
        accusam,
        amet,
        amet,
        aliquyam,
        At,
        accusam,
        amet,
        amet,
        aliquyam,
        At,
        accusam,
        amet
    );
    C =     (
        consetetur,
        clita,
        consetetur,
        clita,
        consetetur,
        clita
    );
    //…
    L =     (
        Lorem,
        labore,
        Lorem,
        Lorem,
        labore,
        Lorem,
        Lorem,
        labore,
        Lorem
    );
    //…
    T =     (
        tempor,
        takimata,
        tempor,
        takimata,
        tempor,
        takimata
    );
    U =     (
        ut,
        ut,
        ut
    );
    V =     (
        voluptua,
        vero,
        voluptua,
        vero,
        voluptua,
        vero
    );
    other =     (
        "%$",
        "!",
        "9)7/",
        1234,
        56hfr
    );
}
0 голосов
/ 26 января 2012

C предоставляет стандартные функции для тестирования различных классов символов, поэтому мы можем сократить ваш код до:

//For each product in the appDelgates products
for (Product *product in appDelegate.m_Products)
{
   if ([product.category isEqualToString:productType])
   {
       //firstLetter is equal to the first letter of the products name in uppercase
       int l_FirstLetter = toupper([product.name characterAtIndex:1]);

       //Place in appropriate section, if none, place in "Other" category
       unsigned index = isupper(l_FirstLetter) ? (l_FirstLetter - 'A') : 26;
       [[m_AlphabetDictionary objectAtIndex:index] addObject:product];
   }
}
0 голосов
/ 26 января 2012

Чтобы уточнить ответ викингосегундо:

for (Product *product in appDelegate.m_Products) {
    if ([product.category isEqualToString: productType]) {
        NSString* l_FirstLetter = [product.name substringToIndex: 1];
        l_FirstLetter = [l_FirstLetter uppercaseString];

        NSInteger key = l_FirstLetter - 'A';
        [[m_AlphabetDictionary objectAtIndex: key] addObject: product];
    }
}

Это если Objective-C позволяет вычесть символ ('A') из строки NSString. Возможно, вам придется сначала преобразовать l_FirstLetter в символ.

...