将.csv读入NSObjects,然后按不同的标准对它们进行排序

时间:2013-01-21 21:21:26

标签: ios objective-c csv

这是一个比错误相关的问题更开放的问题,所以如果你不想回答这些问题,请不要火焰。

我在.csv文件中有一个巨大的(!)船只列表,以,

分隔

矩阵的组织方式如下: enter image description here
用不同的数据重复约500次。

现在,我希望将其读入对象,可以进一步使用它来填充UITableView 目前,我将数据硬编码到目标文件中,如此

arrayWithObjectsForTableView = [[NSMutableArray alloc] init];
if ([boatsFromOwner isEqualToString:@"Owner1"]) {
    cargoShips* ship = [[cargoShips alloc]init];
    ship.name = @"name1";
    ship.size = 1000;
    ship.owner = @"Owner1";

    [self.boatsForOwner addObject:ship];

    ship = [[cargoShips alloc]init];
    ship.name = @"Name 2";
    ship.size = 2000;
    ship.owner = @"Owner2";

依此类推,if-else's。这是一个糟糕的方法,如 1)它很无聊,需要很长时间 2)如果我想更新信息,则需要更多时间。 所以,我认为从矩阵中以编程方式读取而不是自己做它会更聪明。是的,船长显然是为了访问我的大脑。

所以,问题! 如何读取如下所示的.csv文件: enter image description here 以对象的形状将所有者的船只添加到NSMutableArray。 (所以他们可以用来喂我的UITableView船。

我还想选择按照不同的东西排序,例如构建国家,运营商等。如何将从.csv读取的相关船只的代码转换为对象? 我不太了解编程,因此非常感谢深入的答案。

3 个答案:

答案 0 :(得分:11)

处理的深度将决定此任务所需的数据结构类型。这是我将使用的方法:

1:.csv文件读入一个巨大的NSString对象:

NSString *file = [[NSString alloc] initWithContentsOfFile:yourCSVHere];

2:获取各行:

NSArray *allLines = [file componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];

3:对于每一行,请获取各个组件:

for (NSString* line in allLines) {
    NSArray *elements = [line componentsSeparatedByString:@","];
    // Elements now contains all the data from 1 csv line
    // Use data from line (see step 4)
}

4:这取决于您。我的第一个想法是创建一个类来存储你的所有数据。例如:

@interface Record : NSObject
//...
@property (nonatomic, copy) NSString *name
@property (nonatomic, copy) NSString *owner
// ... etc
@end

4a:然后,在步骤3中为每一行创建一个Record对象,然后将所有Record对象放入一个单独的NSArray(范围更大的东西! )。

5:使用包含所有NSArray个对象的Record作为UITableView的数据来源。

第4步和第5步的实施由您决定。对于中等大小的.csv文件,我可能会这样做。

编辑:以下是生成Records的方法。

//
NSMutableArray *someArrayWithLargerScope = [[NSMutableArray alloc] init];
//

NSString *file = [[NSString alloc] initWithContentsOfFile:yourCSVHere];
NSArray *allLines = [file componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet];

for (NSString* line in allLines) {
    NSArray *elements = [line componentsSeparatedByString@","];
    Record *rec = [[Record alloc] init];
    rec.name = [elements objectAtIndex:0];
    rec.owner = [elements objectAtIndex:1];
    // And so on for each value in the line.
    // Note your indexes (0, 1, ...) will be determined by the
    // order of the values in the .csv file.
    // ...
    // You'll need one `Record` property for each value.

    // Store the result somewhere
    [someArrayWithLargerScope addObject:rec];
}

答案 1 :(得分:3)

就CSV解析而言,假设你可以花费内存,它可能最容易在整个事物中读到NSString,在换行符上拆分,然后在逗号上拆分每一行,基本上正如PLPiper建议的那样。

在那一点上,我将绕道进行键值编码。为CSV文件中的列提供与运行时对象上的属性完全相同的名称。然后你可以写出类似的东西:

// this method will create an object of the given type then push the values
// from valueRow to the properties named by headingRow. So, ordinarily,
// headingRow will be the first row in your CSV, valueRow will be any other
- (id)populatedObjectOfType:(Class)type withHeadingRow:(NSArray *)headingRow valueRow:(NSArray *)valueRow
{
    // we need the count of fields named in the heading row to 
    // match the count of fields given in this value row
    if([headingRow count] != [valueRow count]) return nil;

    // autorelease if you're not using ARC
    id <NSObject> newInstance = [[type alloc] init];

    // we need to enumerate two things simultaneously, so
    // we can fast enumerate one but not the other. We'll
    // use good old NSEnumerator for the other
    NSEnumerator *valueEnumerator = [valueRow objectEnumerator];
    for(NSString *propertyName in headingRow)
    {
        [newInstance setValue:[valueEnumerator nextObject] forKey:propertyName];
    }

    return newInstance;
}

... elsewhere ....
CargoShip *newShip = [self populateObjectOfType:[CargoShip class] withHeadingRow:[csvFile objectAtIndex:0] valueFor:[csvFile objectAtIndex:1]];

主要警告是内置机制将在标量和对象之间进行转换,但不会在不同类型的对象之间进行转换。因此,如果您拥有所有NSString和C整数类型(shortintNSUInteger等),那么您可以,但如果您有一些{{ 1}} s,比如一些NSString s,那么你最终会得到存储在数字槽中的字符串。看起来你正在使用C整数类型(这很正常)所以你应该没问题。

在过滤方面,您可以使用NSNumber s。例如,假设您有一个NSPredicate的数组,并希望每个CargoShip至少为500:

size

同样,对于排序,您可以在问题上抛出一些NSArray *bigShips = [allShips filteredArrayUsingPredicate: [NSPredicate predicateWithFormat:@"size > 500"]]; 。 E.g。

NSSortDescriptor

答案 2 :(得分:3)

你可以使用这个链接,
https://github.com/davedelong/CHCSVParser
它是.csv解析器,CHCSVParser可以配置为解析其他“字符分隔”文件格式,例如“TSV”(tab-seperated)或逗号分隔。