Ben Leggiero Ben Leggiero - 4 years ago 116
Objective-C Question

Create a comma-separated list with "and" before the last item in Objective-C, in particular

I want to write a method that provides a human-readable string representation of arrays, with comma-spaces when necessary (incl. the Oxford Comma), and a conjoining " and " at the end.

For example, say I have these arrays:

NSArray *nun = @[];
NSArray *won = @[@"The Loneliest"];
NSArray *too = @[@"Peas", @"Pod"];
NSArray *tree = @[@"Apple", @"Falls", @"Far, Far Away"];

I want to write a method like:

+ (NSString*) humanReadableListFromArray: (NSArray*) arr
// magic

And when I pass my arrays through, I want them to look like this:

@"The Loneliest"
@"Peas and Pod"
@"Apple, Falls, and Far, Far Away"

Note that the first one, having exactly 1 item, is just the first item without decoration. The second, having exactly 2 items, has no commas, but does have the conjoining " and ". The third, having more than 2 items, includes a comma-space between each item, and the last item includes an additional
just after the comma-space and before the item.

Is there a short way to do this in Objective C? I've done this in languages like Java, but I know that Objective C features methods like
-(NSString*)[NSArray componentsJoinedByString:]
that might assist in this.

This question is not answered by Replace last comma in string with an "and". (Objective-C) because it does not address commas in the last array item. I've also looked into questions like Objective-C Simplest way to create comma separated string from an array of objects, and they don't mention this nice part of human readability.

Answer Source

That third party library @timgcarlson mentions sounds promising. Here's what I'd do natively...

- (NSString *)humanReadableListFromArray:(NSArray *)array withOxfordStyle:(BOOL)oxford {
    if (array.count == 0) return @"";
    if (array.count == 1) return array[0];
    if (array.count == 2) return [array componentsJoinedByString:@" and "];

    NSArray *firstItems = [array subarrayWithRange:NSMakeRange(0, array.count-1)];
    NSString *lastItem = [array lastObject];
    NSString *lastDelimiter = (oxford)? @", and " : @" and ";
    return [NSString stringWithFormat:@"%@%@%@",
        [firstItems componentsJoinedByString:@", "], lastDelimiter, lastItem];
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download