【问题标题】:Collection Enumeration Searching for Strings in Order集合枚举按顺序搜索字符串
【发布时间】:2014-02-17 19:05:17
【问题描述】:

我有一个包含 500 个字符串 (NSString) 的数组,每个字符串仅代表一个字符(例如:@"H"),我将从头到尾循环遍历。

在这些字符串中,例如有 @"H"@"e"@"l"@"l"@"o" 等字符串。

它们肯定在数组中,但顺序未知。

我想从头到尾循环遍历数组并想打印出来 “你好”没有重复。就一次。并且字符串@"H" 必须首先出现在“ello”之前。

所以当第一个@"H" 出现时,我会开始寻找其余的“ello”并将它们打印出来。

过去一个小时一直在思考这个问题,但不幸的是,除了以下几点:

也许有一些条件,例如NSPredicate 等,我可以在循环发生之前先按顺序找到这些字符串的索引号。因此,当我循环遍历数组并因此使用一堆if-else 时,我可以将它们打印出来而无需检查。

例如:

NSArray *indexesThatMatchTheStrings = [......(condition => @"H", @"e", @"l", @"l", @"o").....]'

indexesThatMatchTheStrings 将包含匹配的索引。如果条件不满足,那么我会事先知道我不必打印出来。同样,数组中有“H”、“e”、“l”、“l”、“o”,但顺序很重要。

集合中有这样的操作吗?我对任何类型的集合和算法持开放态度(即NSSetNSArrayNSDictionary 等)。甚至C 中的方法(位移、结构、内存比较等)。有些东西又快又轻。

附录:

概括一下用例:

框架是否提供了任何方法或方法,我们可以通过这些方法或方法为数组、字典或集合等集合设置测试条件,我们可以根据这些方法来确定其中是否存在某些东西一个特定的条件(在我的例子中:h e l l o 序列),以便我们可以最小化循环+比较开销?或者甚至完全避免循环+搜索的需要,因为我们知道集合不满足搜索条件?

【问题讨论】:

  • 您能否举例说明您正在从示例输入中寻找的确切输出?我可以根据您的描述想到几个场景,只是想得到您想要的。
  • 让我们抽象地看待这个问题,所以我们首先找到“H”,然后我们进一步迭代找到“E”,然后是字符串的其余部分。我是否正确理解了您的问题?
  • @Putz1103 感谢您的回复。这个数组中有字符,“H”、“e”、“l”、“l”、“o”肯定在那里(每个字符在这个数组中可以有重复,但顺序未知)。我想通过使用集合中的一些快速枚举技术/方法来检查其中是否存在连续字符“H”“e”“l”“l”“o”。
  • @Basheer_CAD 你对我的理解是正确的。谢谢。

标签: ios objective-c c collections nspredicate


【解决方案1】:

这是我的版本:

NSArray * allChars = @[@"l", @"A", @"B", @"H", @"b", @"e", @"H", @"c", @"c", @"l", @"b", @"q", @"l", @"l", @"l", @"z", @"o", @"H", @"e", @"l",@"l", @"o", @"l"];
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"SELF in[cd] %@", @[@"H", @"e", @"l", @"o"]];
NSArray * equal = [allChars filteredArrayUsingPredicate:predicate];
NSString * sayHello = @"";

// This loop will find any sequence of Hello's characters

for (int i=0; i<equal.count; i++)
{
    NSString * nextChar = equal[i];
    NSString * try = [sayHello stringByAppendingString:nextChar];

    if ([@"Hello" rangeOfString:try].location == 0) {
        sayHello = try;
    }

    if ([sayHello rangeOfString:@"Hello"].location != NSNotFound) {
        NSLog(@"Hello!");
        break;
    }
}

// This loop works if between Hello's char cannot be any other characters

sayHello = @"";

for (int i=0; i<equal.count; i++)
{
    sayHello = [sayHello stringByAppendingString:equal[i]];
    if ([sayHello rangeOfString:@"Hello"].location != NSNotFound) {
        NSLog(@"Hello!");
        break;
    }
}

return YES;

编辑:感谢编写正则表达式的@melvas's,我用 NSRegularExpression 做了同样的事情并且没有循环:

    NSString * possibleHello = [equal componentsJoinedByString:@""];    
    NSString * regex = @"(?=(h|H))(.*?)(?=(e|E))(.*?)(?<=(l|L))(.*?)(?=(l|L))(.*?)(?=(o|O))";

    NSError * error = nil;        
    NSRegularExpression * regularExp = [NSRegularExpression regularExpressionWithPattern:regex
                                                                                 options:NSRegularExpressionDotMatchesLineSeparators
                                                                                   error:&error];
    NSArray * matches = [regularExp matchesInString:possibleHello
                                            options:NSMatchingReportProgress
                                              range:NSMakeRange(0, posibleHello.length)];
    if (matches.count) {
        NSLog(@"Hello!");
    }

【讨论】:

  • +1 用于使用谓词。会试一试,但我也很想知道是否可以在不循环的情况下检查数组中的条件(在我的示例中:例如,hello 字符串序列)并与使用某些方法进行比较在 Objective-C 集合中。
  • 我想过这个,但似乎不可能,因为双'l'。当您将 [NSSet setWithArray: equal] 删除重复项时,您还将删除 'll'
  • 如果只有一个 'l' 是否可以不使用循环?
  • 当然,NSSet * set = [NSSet setWithArray:equal]; NSString * posibleHello = [set.allObjects componentsJoinedByString:@""];possibleHello 将包含反转的 'oleH' 字,因此您需要将其与反转的字进行比较)
【解决方案2】:

鉴于我对您的问题的解释,您的问题的第一个答案(这是假设您无论如何都在循环遍历您的数组):

您知道要查找的字符以及查找它们的顺序(我假设)。所以创建一个你想要的对象数组和你想要的确切顺序。然后遍历数据数组并根据已知数组和该数组中的当前位置检查每个对象。然后打印,保存,用那里的信息做任何事情。

NSArray *knownArray = [NSArray arrayWithObjects:@"H", @"e", @"l", @"l", @"o", nil];
int currentLocationInKnownArray = 0;
for(int i = 0; i < [data count]; i++)
{
    if([[data objectAtIndex:i] isEqualToString:[knownArray objectAtIndex:currentLocationInKnownArray]])
    {
        //You found a match
        currentLocationInKnownArray++;

        //Do whatever else you would like with the index or data from this loop.
    }
}

//Now check if you found your complete set
if(currentLocationInKnownArray == [knownArray count])
{
    //You found them all in order in your array.
}

如果你无论如何都不打算迭代你的数组,那么你可以在 NSArray 中使用不同的函数(这可能比单个循环花费更长的时间,因为我们多次迭代整个数组,但 Apple 可能已经优化这些功能有点):

NSArray *knownArray = [NSArray arrayWithObjects:@"H", @"e", @"l", @"l", @"o", nil];

__block int currentIndexInMaster = 0;
for(int i = 0; i < [knownArray count]; i++)
{
    __block bool validObjectFound = false;
    NSIndexSet *set = [data indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
        if([(NSString*)obj isEqualToString:[knownArray objectAtIndex:i]])
        {
            return true;
        }
        return false;
    }];

    [set enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
        //... do something with idx
        // *stop = YES; to stop iteration early
        if(idx > currentIndexInMaster)
        {
            currentIndexInMaster = idx;
            validObjectFound = true;
            *stop = TRUE;
        }
    }];

    if(!validObjectFound)
    {
        //No longer valid data, do not continue
        break;
    }

}

【讨论】:

  • 谢谢+1,我会试一试的。 enumerateUsingBlock 对我来说并不陌生。就我而言,是的,无论如何我都需要遍历整个数组。但也很奇怪,我们可以在集合(例如数组)上放置一个条件,并事先知道某些东西是否确实在数组中,以便可以最小化或完全避免循环+比较。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-23
  • 1970-01-01
  • 2017-12-06
相关资源
最近更新 更多