vendredi 3 février 2012

Les tableaux jumelés à Cocoa et Cocoa Touch

Le concept de «tableaux jumelés" est vraiment un puissant. L'idée de base est-ce - que vous avez NSArrays multiples ou NSMutableArrays, et ils détiennent des valeurs correspondant à la même chose. Par exemple, vous pourriez avoir un tableau de clés et l'une des valeurs. C'est un simple exemple, et celui où vous n'auriez probablement juste utiliser une NSDictionary, mais c'est un bon exemple pour montrer ce qu'ils sont utilisés pour. Maintenant, le premier élément dans un tableau correspond à l'élément premier dans l'autre tableau. Cela vous donne plus de souplesse que d'utiliser une NSDictionary parce que vous avez un accès rapide à chaque liste et peuvent également avoir plus de deux tableaux appariés, vous n'êtes donc pas restreinte à clé et la valeur, vous pourriez avoir trois valeurs clés et par exemple, sans avoir à déranger avec des dictionnaires à l'intérieur des dictionnaires.

J'utilise cette technique beaucoup avec SQLitePersistentObjects sur l'iPhone pour éviter de charger des objets en mémoire juste pour afficher une ou deux valeurs à partir d'un objet, par exemple, à mettre dans un tableau. Lorsque vous avez des objets qui contiennent UIImages ou NSDatas, en faisant cela peut vraiment garder votre chemin empreinte mémoire vers le bas, qui est une très bonne chose sur un dispositif de ressources limitées. Sur l'iPhone, je suis un grand fan de tableaux appariés. Je ne les utilisez pas tellement sur le Mac, mais ils ont certainement leurs utilisations.

Mais, il ya une chose vraiment gênant sur les tableaux appariés: les triant. C'est juste pas drôle. NSMutableArray est mis en place pour trier en fonction des valeurs de son propre réseau, et non sur les valeurs dans un autre tableau. Donc, si vous voulez trier la fois la clé et les tableaux de valeur fondée sur les valeurs dans le tableau de clés, comment voulez-vous faire? Il n'ya pas facile, moyen intégré.

Eh bien, si vous avez suivi ce blog, pour toute longueur de temps, vous savez que j'ai vraiment, vraiment, comme l'Objective-C les catégories. Voici une nouvelle - il vous permet de trier des tableaux multiples basées sur les valeurs dans un tableau. Il utilise exactement l'algorithme de tri même que NSMutableArray je crois - une sorte coquille. Je ne travaille pas pour Apple et n'ont pas accès à leur code, donc je ne sais pas pour sûr qu'ils ont encore le faire de cette façon, mais l'ancien NeXTStep / OpenStep tri a été fait de cette façon, et le genre GNUStep est toujours fait de cette façon, donc je suppose que Apple Foundation Kit version de NSMutableArray fonctionne toujours de cette façon, si je ne suis certainement ouvert à d'autres algorithmes de tri optimisé, si vous voulez modifier.

Voici un exemple d'utilisation de cette catégorie, en utilisant trois tableaux jumelés, l'un avec des chiffres, et deux autres avec ces chiffres énoncés dans des langues différentes, et le tri des trois valeurs basées sur les chiffres.

    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSNumber numberWithInt:5], [NSNumber numberWithInt:3], [NSNumber numberWithInt:1], [NSNumber numberWithInt:2], [NSNumber numberWithInt:4], [NSNumber numberWithInt:6], nil];
NSMutableArray *array2 = [NSMutableArray arrayWithObjects:@"Five", @"Three", @"One", @"Two", @"Four", @"Six", nil];
NSMutableArray *array3 = [NSMutableArray arrayWithObjects:@"Cinq", @"Trois", @"Un", @"Deux", @"Quatre", @"Six", nil];

[array1 sortArrayUsingSelector:@selector(compare:) withPairedMutableArrays:array2, array3, nil];

Après l'appel à sortArrayUsingSelector: withPairedArrays: les trois tableaux seront tous dans l'ordre numérique, de sorte array2 ressemblera à ceci:
One, Two, Three, Four, Five, Six
et tableau3 ressemblera à ceci:
Un, Deux, Trois, Quatre, Cinq, Six
Plutôt cool, hein? Voici le code:

NSMutableArray-MultipleSort.h
//
// NSMutableArray-MultipleSort.h
// iContractor
//
// Created by Jeff LaMarche on 1/16/09.
// Copyright 2009 Jeff LaMarche. All rights reserved.
//

// This category on NSMutableArray implements a shell sort based on the old NeXT example
// SortingInAction. It is functionally identical to sortArrayUsingSelector: except that
// it will sort other paired arrays based on the comparison values of the original array
// this is for use in paired array situations, such as when you use one array to store
// keys and another array to store values. This is a variadic method, so you can sort
// as many paired arrays as you have.

// This source may be used, free of charge, for any purposes. commercial or non-
// commercial. There is no attribution requirement, nor any need to distribute
// your source code. If you do redistribute the source code, you must
// leave the original header comments, but you may add additional ones.


// Stride factor defines the size of the shell sort loop's stride. It can be tweaked
// for performance, though 3 seems to be a good general purpose value
#define STRIDE_FACTOR 3

#import <Foundation/Foundation.h>

// This compare method was taken from the GNUStep project. GNUStep is
// licensed under the LGPL, which allows such use.
static inline NSComparisonResult compare(id elem1, id elem2, void* context)
{
NSComparisonResult (*imp)(id, SEL, id);

if (context == 0)
{
[NSException raise: NSInvalidArgumentException
format: @"compare null selector given"
]
;
}

imp = (NSComparisonResult (*)(id, SEL, id))
[elem1 methodForSelector: context];

if (imp == NULL)
{
[NSException raise: NSGenericException
format: @"invalid selector passed to compare"
]
;
}

return (*imp)(elem1, context, elem2);
}

@interface NSMutableArray(MultipleSort)
// Takes a comparator and a nil-terminated list of paired arrays
- (void)sortArrayUsingSelector:(SEL)comparator withPairedMutableArrays:(NSMutableArray *)array1, ...;
@end



NSMutableArray-MultipleSort.m
//
// NSMutableArray-MultipleSort.m
// iContractor
//
// Created by Jeff LaMarche on 1/16/09.
// Copyright 2009 Jeff LaMarche Consulting. All rights reserved.
//
// This source may be used, free of charge, for any purposes. commercial or non-
// commercial. There is no attribution requirement, nor any need to distribute
// your source code. If you do redistribute the source code, you must
// leave the original header comments, but you may add additional ones.

#import "NSMutableArray-MultipleSort.h"

@implementation NSMutableArray(MultipleSort)
- (void)sortArrayUsingSelector:(SEL)comparator withPairedMutableArrays:(NSMutableArray *)array1, ...
{
unsigned int stride = 1;
BOOL found = NO;
unsigned int count = [self count];
unsigned int d;

while (stride <= count)
stride = stride * STRIDE_FACTOR + 1;

while (stride > (STRIDE_FACTOR - 1))
{
stride = stride / STRIDE_FACTOR;
for (unsigned int c = stride; c < count; c++)
{
found = NO;
if (stride > c)
break;

d = c - stride;
while (!found)
{
id a = [self objectAtIndex: d + stride];
id b = [self objectAtIndex: d];

NSComparisonResult result = (*compare)(a, b, (void *)comparator);

if (result < 0)
{
[a retain];
[self replaceObjectAtIndex: d + stride withObject: b];
[self replaceObjectAtIndex: d withObject: a];

id eachObject;
va_list argumentList;
if (array1)
{
id a1 = [array1 objectAtIndex:d+stride];
id b1 = [array1 objectAtIndex:d];
[a1 retain];
[array1 replaceObjectAtIndex: d + stride withObject:b1];
[array1 replaceObjectAtIndex: d withObject: a1];
[a1 release];
va_start(argumentList, array1);
while (eachObject = va_arg(argumentList, id))
{
id ax = [eachObject objectAtIndex:d+stride];
id bx = [eachObject objectAtIndex:d];
[ax retain];
[eachObject replaceObjectAtIndex: d + stride withObject:bx];
[eachObject replaceObjectAtIndex: d withObject: ax];
[ax release];
}
va_end(argumentList);
}

[a release];

if (stride > d)
break;

d -= stride;
}
else
found = YES;
}
}
}
}
@end



Aucun commentaire: