Print symbols that were met in the text, no duplicates - ios

I have been struggling with this question for couple days now. Really need your help and opinion.
We have a string, that holds a text:
NSString *contentOfFile = [[NSString alloc] initWithString:#"This is string#1"];
Now I have to log symbols, that were met in this string without duplicates. Result should look like this:
whitespace symbol here
#
1
g
h
i
n
r
s
t
I know that this is solved very simple in C code using char set and iterators but I am looking for the same simple and elegant way of handling this operation in objective-c.
I was thinking of using NSCharacterSet on the string somehow but I have a lack of knowledge in objective-c so I need your help guys please. Thanks in advance to everyone who replies.

Take advantage of a trait of NSSet: Its members are distinct.
NSString *contentOfFile = #"This is string#1";
NSMutableSet *set = [NSMutableSet set];
NSUInteger length = [contentOfFile length];
for (NSUInteger index = 0; index < length; index++)
{
NSString *substring = [contentOfFile substringWithRange:NSMakeRange(index, 1)];
[set addObject:substring];
}
NSLog(#"%#", set);
However, there's one remaining problem, and that is the members of a set are also unordered. Fortunately, arrays are ordered. So if you change the last line:
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"self" ascending:YES];
NSArray *array = [set sortedArrayUsingDescriptors:#[sortDescriptor]];
NSLog(#"%#", array);
If case insensitivity is important to you, there unfortunately is no 'case-insensitive' option for NSSet. However, you could convert your source string to all lowercase, like this:
NSString *contentOfFile = [#"This is string#1" lowercaseString];
and this would give you results exactly matching your sample output.

// Create the string
NSString *contentOfFile = #"This is string#1";
// Remove all whitespaces
NSString *whitespaceRemoval = [contentOfFile stringByReplacingOccurrencesOfString:#" " withString:#""];
// Initialize an array to store the characters
NSMutableArray *components = [NSMutableArray array];
// Iterate through the characters and add them to the array
for (int i = 0; i < [whitespaceRemoval length]; i++) {
NSString *character = [NSString stringWithFormat:#"%c", [whitespaceRemoval characterAtIndex:i]];
if (![components containsObject:character]) {
[components addObject:character];
}
}

Related

IOS:Objective-C: How to combine elements of arrays

I have an array of people objects stored in Core Data and I would like to create a string made by combining two attributes of each, as in firstname and lastname.
NSArray *firstArr = [[Employees valueForKey:#"first"] allObjects];
NSArray *secondArr = [[Employees valueForKey:#"last"] allObjects];
I can create a string from one attribute such as "John,Jane" with
NSString *firststr = [firstarr componentsJoinedByString:#","];
Can anyone suggest how to make a string that has the first and last names separated by commas as in John Doe, Jane Doe? Imagine there is a method but I cannot find it.
You can do it like this
NSArray *firstArr = #[#"Rajat" , #"Rajat1", #"Raj"];
NSArray *secondArr = #[#"Test" , #"Test1", #"Test2"];
NSString * str = #"";
for (int i=0; i< (firstArr<secondArr ? firstArr.count:secondArr.count); i++) {
str = [str stringByAppendingString:[NSString stringWithFormat:#"%# %#,",firstArr[i],secondArr[i]]];
}
str = [str substringToIndex:[str length]-1];
NSLog(#"%#",str);

iOS - Displaying Two Words At A Time From String Array

I'm doing an RSVP reading project app where it blinks words on the screen. You can set the word chunk size (how many words you want displayed at a time) to either 1, 2, or 3. I got it working for 1 word by having my paragraph in a string and doing:
[self.textInput componentsSeparatedByString:#" ";
This makes me an array of words that I can use to blink one word at a time. How would I be able to do this with displaying 2 words at a time? Is there a way I can use this function again to do it differently, or should I iterate over this word array and make a new one with 2 word strings?
Any help or advice would be greatly appreciated as to what the best practice would to get this done. Thanks.
just like keith said create an array
NSArray *allwordsArray = [self.textInput componentsSeparatedByString:#" "];
Now you got all the info you need. Meaning you got the array with every word in it. Now its just a matter of putting it together. (I haven't tested this code)
NSMutableArray *twoWordArray = [[NSMutableArray alloc] init];
int counter=0;
for (int i=0; i<[allwordsArray count]; i++)
{
if (counter >= [allwordsArray count]) break;
NSString *str1 = [NSString stringwithformat#"%#", [allwordsArray objectAtIndex:counter]];
counter++;
if (counter >= [allwordsArray count]) break;
NSString *str2 = [NSString stringwithformat#"%#", [allwordsArray objectAtIndex:counter]];
NSString *combinedStr = [NSString stringwithformat#"%# %#", str1,str2];
[twoWordArray addObject: combinedStr];
counter++;
}
You have broken the string into components, which is on the right track. You could then make a smaller array that only includes components until you reach the chunk size. The final step would be to rejoin the string.
NSArray *components = [self.textInput componentsSeparatedByString:#" "];
NSRange chunkRange = NSMakeRange(0, chunkSize);
NSArray *lessComponents = [components subarrayWithRange:chunkRange];
NSString *newString = [lessComponents componentsJoinedByString:#" "];

ios FMDB SELECT NOT IN (?)

I would like to check if an id list is in the database.
Here is my code...
NSArray *array = [NSArray arrayWithObjects:#"1",#"2",#"3",nil];
NSString *string = [array componentsJoinedByString:#","];
FMResultSet * rs = [self.db executeQuery:#"SELECT id FROM FriendList WHERE id NOT IN (?)",string];
It's doesn't work. It's only work if array only has a single number.
Anyone knows how to do SELECT NOT IN using FMDB?
Thanks!
You need little modification here.
Follow below code.
NSArray *array = [NSArray arrayWithObjects:#"1",#"2",#"3",nil];
NSString *components = [array componentsJoinedByString:#", "];
NSMutableString *valueString = [NSMutableString new];
NSMutableString *fieldString = [NSMutableString new];
[fieldString appendString:#"SELECT id FROM FriendList WHERE id NOT IN ("];
for (NSString *fielValue in array) {
[fieldString appendString:#"?,"];
[valueString appendString:fielValue];
}
[fieldString replaceCharactersInRange:NSMakeRange([fieldString length] - 1, 1) withString:#")"];
NSString *normalString = [NSString stringWithString:fieldString];
fieldString = nil;
FMResultSet * rs = [self.db executeQuery:#"%#", normalString, components];
EDIT:
From the information you provide me in a comments, I did figure out that sqlite is not able to compile the string literal while you provide multiple items from array components. I modify answer still it's from your end to test that it is working or not? Leave a comment for acknowledgment.

How to convert elements of NSMutableArray (NString) to NSNumber and add them up?

Ok so I have NsMutable array with Strings which are in format:
32,45,54,5550 etc.
What is the easiest way to convert all these strings to nsnumber and also get the sum of entire array.
You can use the KVC collection operator #sum to get the summation of all number strings stored in an array
NSArray *numberStrings = #[#"32",#"45",#"54",#"5550"];
NSNumber* sum = [numberStrings valueForKeyPath: #"#sum.self"];
NSLog(#"%#", sum);
output: 5681
For simple strings it works. But caution: in localization there might be traps. There-for I would still suggest to use a NSNumberFormatter to create real NSNumber objects, store them in another array and use #sum on that.
Thanks Bryan Chen for make me test.
To raise the awareness for problems that might lie in localization, I want to share this experiment with you:
In German we use , to separate the decimal digits, where as we use the . to group long numbers in thousands.
So if the numberString array might be filled with german formatted numbers, it might look like #[#"32,5", #"45", #"54", #"5.550,00"]. The sum of this is 5681.5, but if we do not alter the code, it will not fail, but worse — miscalculate: 136.55. It just ignored everything past a comma and treated . as decimal separator.
Lets use a NSNumberFormatter to fix it:
My system is set to german locale
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.locale = [NSLocale currentLocale];
[nf setGroupingSize:3];
nf.usesGroupingSeparator= YES;
NSArray *numberStrings = #[#"32,5", #"45", #"54", #"5.550,00"];
NSMutableArray *numbers = [#[] mutableCopy];
for (NSString *s in numberStrings) {
NSNumber *n = [nf numberFromString:s];
[numbers addObject:n];
}
NSNumber* sum = [numbers valueForKeyPath: #"#sum.self"];
NSLog(#"%#", sum);
it prints correctly 5681.5.
NSArray *array = #[ #"1,2", #"3,4" ];
NSUInteger sum = 0;
for (NSString *str in array)
{
for (NSString *num in [str componentsSeparatedByString:#","])
{
sum += [num intValue];
}
}
or
NSArray *array = #[ #"1", #"3" ];
NSUInteger sum = 0;
for (NSString *num in array)
{
sum += [num intValue];
}

Regex in objective C

I want to extract only the names from the following string
bob!33#localhost #clement!17#localhost jack!03#localhost
and create an array [#"bob", #"clement", #"jack"].
I have tried NSString's componentsseparatedbystring: but it didn't work as expected. So I am planning to go for regEx.
How can I extract strings between ranges and add it to an array
using regEx in objective C?
The initial string might contain more than 500 names, would it be a
performance issue if I manipulate the string using regEx?
You can do it without regex as below (Assuming ! sign have uniform pattern in your all words),
NSString *names = #"bob!33#localhost #clement!17#localhost jack!03#localhost";
NSArray *namesarray = [names componentsSeparatedByString:#" "];
NSMutableArray *desiredArray = [[NSMutableArray alloc] initWithCapacity:0];
[namesarray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSRange rangeofsign = [(NSString*)obj rangeOfString:#"!"];
NSString *extractedName = [(NSString*)obj substringToIndex:rangeofsign.location];
[desiredArray addObject:extractedName];
}];
NSLog(#"%#",desiredArray);
output of above NSLog would be
(
bob,
"#clement",
jack
)
If you still want to get rid of # symbol in above string you can always replace special characters in any string, for that check this
If you need further help, you can always leave comment
NSMutableArray* nameArray = [[NSMutableArray alloc] init];
NSArray* youarArray = [yourString componentsSeparatedByString:#" "];
for(NSString * nString in youarArray) {
NSArray* splitObj = [nString componentsSeparatedByString:#"!"];
[nameArray addObject:[splitObj[0]]];
}
NSLog(#"%#", nameArray);
I saw the other solutions and it seemed no one tried to use real regular expressions here, so I created a solution which uses it, maybe you or someone else can use it as a possible idea in the future:
NSString *_names = #"bob!33#localhost #clement!17#localhost jack!03#localhost";
NSError *_error;
NSRegularExpression *_regExp = [NSRegularExpression regularExpressionWithPattern:#" ?#?(.*?)!\\d{2}#localhost" options:NSRegularExpressionCaseInsensitive error:&_error];
NSMutableArray *_namesOnly = [NSMutableArray array];
if (!_error) {
NSLock *_lock = [[NSLock alloc] init];
[_regExp enumerateMatchesInString:_names options:NSMatchingReportProgress range:NSMakeRange(0, _names.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
if (result.numberOfRanges > 1) {
if ([_lock tryLock]) [_namesOnly addObject:[_names substringWithRange:[result rangeAtIndex:1]]], [_lock unlock];
}
}];
} else {
NSLog(#"error : %#", _error);
}
the result can be logged...
NSLog(#"_namesOnly : %#", _namesOnly);
...and that will be:
_namesOnly : (
bob,
clement,
jack
)
Or even something as simple as this will do the trick:
NSString *strNames = #"bob!33#localhost #clement!17#localhost jack!03#localhost";
strNames = [[strNames componentsSeparatedByCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]]
componentsJoinedByString:#""];
NSArray *arrNames = [strNames componentsSeparatedByString:#"localhost"];
NSLog(#"%#", arrNames);
Output:
(
bob,
clement,
jack,
""
)
NOTE: Ignore the last element index while iterating or whatever
Assumption:
"localhost" always comes between names
I know it ain't so optimized but it's one way to do this

Resources