Get unique artist names from MPMediaQuery - iphone

I am using MPMediaQuery to get all artists from library. Its returning unique names I guess but the problem is I have artists in my library like "Alice In Chains" and "Alice In Chains ". The second "Alice In Chains" has some white spaces at the end, so it returns both. I dont want that. Heres the code...
MPMediaQuery *query=[MPMediaQuery artistsQuery];
NSArray *artists=[query collections];
artistNames=[[NSMutableArray alloc]init];
for(MPMediaItemCollection *collection in artists)
{
MPMediaItem *item=[collection representativeItem];
[artistNames addObject:[item valueForProperty:MPMediaItemPropertyArtist]];
}
uniqueNames=[[NSMutableArray alloc]init];
for(id object in artistNames)
{
if(![uniqueNames containsObject:object])
{
[uniqueNames addObject:object];
}
}
Any ideas?

One possible workaround would be to test the artist names for leading and/or trailing whitespace. You could inspect the first and last character of the string for membership with NSCharacterSet whitespaceCharacterSet. If true, then trim all leading and/or trailing whitespace using the NSString stringByTrimmingCharactersInSet method. Then you could add either the trimmed string or the original string to a NSMutableOrderedSet. The ordered set will only accept distinct objects so no duplicate artist names will be added:
MPMediaQuery *query=[MPMediaQuery artistsQuery];
NSArray *artists=[query collections];
NSMutableOrderedSet *orderedArtistSet = [NSMutableOrderedSet orderedSet];
for(MPMediaItemCollection *collection in artists)
{
NSString *artistTitle = [[collection representativeItem] valueForProperty:MPMediaItemPropertyArtist];
unichar firstCharacter = [artistTitle characterAtIndex:0];
unichar lastCharacter = [artistTitle characterAtIndex:[artistTitle length] - 1];
if ([[NSCharacterSet whitespaceCharacterSet] characterIsMember:firstCharacter] ||
[[NSCharacterSet whitespaceCharacterSet] characterIsMember:lastCharacter]) {
NSLog(#"\"%#\" has whitespace!", artistTitle);
NSString *trimmedArtistTitle = [artistTitle stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[orderedArtistSet addObject:trimmedArtistTitle];
} else { // No whitespace
[orderedArtistSet addObject:artistTitle];
}
}
You can also return an array from the ordered set if you need it:
NSArray *arrayFromOrderedSet = [orderedArtistSet array];

Related

Searching for a keyword in a string, in an NSArray

I've got an array of keywords and an array of strings.
I'm currently iterating out the keywords and using a filter on the strings array to determine whether or not the keyword is in there (in some form).
The below code works, however when there is a keyword (or the same characters as the keyword) within another word, this is flagged. ie. Searching for bon in string ribbon would flag ribbon. I don't want to do an exact comparison as it's possible the keyword will be surrounded by other characters / words in the string.
Is there a way I can search for it and only flag it if it's surrounded by whitespace or brackets? ie. Not part of another word..
NSArray *paInc = [productIncludes valueForKey:pa];
// This is the array of keywords
NSMutableArray *paMatchedIncludes = [[NSMutableArray alloc] init];
for (id include in paInc){
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains [cd] %#", include];
NSArray *filteredArray = [stringArray filteredArrayUsingPredicate:predicate];
// stringArray is the array containing the strings I want to search for these keywords
for (NSString *ing in filteredArray){
if ([ing length] > 0){
if (![paMatchedIncludes containsObject:[NSString stringWithFormat:#"%#",ing]]){
[paMatchedIncludes addObject:[NSString stringWithFormat:#"%#",ing]];
}
}
}
}
Does the following code solve your problem?
NSArray *paInc = #[#"bon",
#"ssib"];
// This is the array of keywords
NSArray *stringArray = #[#"Searching for bon in string ribbon would flag ribbon.",
#"I don't want to do an exact comparison as it's possible the keyword will be surrounded by other characters / words in the string."];
// stringArray is the array containing the strings I want to search for these keywords
NSMutableArray *paMatchedIncludes = [[NSMutableArray alloc] init];
for (id include in paInc){ // for every keyword
for (NSString *nextString in stringArray) { // for every string
NSArray *components = [nextString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" ()"]];
if ([components containsObject:include]) {
[paMatchedIncludes addObject:nextString];
}
}
}
EDIT (due to your comment): For case insensitive compares:
for (id include in paInc){ // for every keyword
for (NSString *nextString in stringArray) { // for every string
NSArray *components = [nextString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" ()"]];
for (NSString *nextComponent in components) {
if([nextComponent caseInsensitiveCompare:include] == NSOrderedSame)
[paMatchedIncludes addObject:nextString];
}
}
}
I guess regular expression is what you want.

Compare two strings and remove common elements

I have two comma seperated NSString's & I want to remove the similar characters from first string only.
ex. str1 = 0,1,2,3
str2 = 1,2.
output -> str1 = 0,3 and str2 = 1,2.
I have one option that, seperate both the string with comma seperated values in a array. But it requires two NSArray's & apply loop and then remove the common elements, but it is very tedious job.
So I want some simple & proper solution which avoid the looping.
kindly help me to sort out this.
Try this one:
No loop is required!!!
You have got all the required APIs.
NSString *str1=#"0,1,2,3";
NSString *str2=#"1,2";
NSMutableArray *arr1=[[NSMutableArray alloc]initWithArray:[str1 componentsSeparatedByString:#","]];
[arr1 removeObjectsInArray:[str2 componentsSeparatedByString:#","]];
NSLog(#"arr1 %#",arr1);
/*
NSMutableString *finalString=[NSMutableString new];
for (NSInteger i=0; i<[arr1 count]; i++) {
NSString *str=[arr1 objectAtIndex:i];
[finalString appendString:str];
if (i!=[arr1 count]-1) {
[finalString appendString:#","];
}
}
*/
NSString *finalString=[arr1 componentsJoinedByString:#","];
NSLog(#"finalString %#",finalString);
Something like that ?
NSString *string = #"0,1,2,3";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self like '1' OR self like '2'"];
NSLog(#"%#",[[string componentsSeparatedByString:#","] filteredArrayUsingPredicate:predicate]);
id str1=#"aa,ab,ac,cd,ce,cf";
id str2=#"aa,ac,cd,cf";
//no ab and no ce
id cmps1 = [str1 componentsSeparatedByString:#","];
id cmps2 = [str2 componentsSeparatedByString:#","];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"NOT SELF IN %#", cmps2];
NSArray *final = [cmps1 filteredArrayUsingPredicate:predicate];
id str = [final componentsJoinedByString:#","];
NSLog(#"%#", str);
The only solution that I can think of would be this:
NSMutableArray* arr1 = [str1 componentsSeparatedByString:#","] mutableCopy];
NSArray* arr2 = [str2 componentsSeparatedByString:#","];
for (NSString* str in arr2) {
[arr1 removeObject:str];
}
NSString* newString1 = [arr1 componentsJoinedByString:#","];
Is this what you tried? If "str1" looks something like "1,1,2,2,2", then you might have some more work to do here to get rid of the duplicates. But that's basically it.

How to create a comma-separated string?

I want to create a comma-separated string like this.
NSString *list = #"iPhone,iPad,iPod";
I tried like this,
[strItemList appendString:[NSString stringWithFormat:#"%#,", [[arrItems objectAtIndex:i]objectForKey:#"ItemList"]]];
But the issue is I'm getting a string like this
#"iPhone,iPad,iPod," Note that there is an extra comma "," at the end of the string. How can I avoid that extra comma?
Can you please give me a hint. Highly appreciated
Thanks in advance
To join an array of strings into a single string by a separator (character which would be a string), you could use this method of NSArray class:
NSArray* array = #[#"iPhone", #"iPad", #"iPod"];
NSString* query = [array componentsJoinedByString:#","];
By using this method, you won't need to drop the last extra comma (or whatever) because it won't add it to the final string.
There's a couple of routes you can take.
If the number of items is always the same, and known before hand (which I guess isn't the case, but I mention it for completeness's sake), just make the whole string at once:
[NSString stringWithFormat:#"%#,%#,%#", [[arrItems objectAtIndex:0] objectForKey:#"ItemList"]], [[arrItems objectAtIndex:1] objectForKey:#"ItemList"]], [[arrItems objectAtIndex:2] objectForKey:#"ItemList"]]
Knowing that the unwanted comma will always be the last character in the string, you can make removing it the last step in construction:
} // End of loop
[strItemList removeCharactersInRange:(NSRange){[strItemList length] - 1, 1}];
Or you can change your thinking a little and do the loop like this:
NSString * comma = #"";
for( i = 0; i < [arrItems count]; i++ ){
[strItemList appendString:[NSString stringWithFormat:#"%#%#", comma, [[arrItems objectAtIndex:i]objectForKey:#"ItemList"]]];
comma = #",";
}
Notice that comma comes before the other item. Setting that string inside the loop means that nothing will be added on the first item, but a comma character will be for every other item.
After Completion of loop add below stmt
strItemList = [strItemList substringToIndex:[strItemList length]-1]
check the value of array count if array count is last then add without comma else add with comma. try this out i am not sure to much about.
if([arrItems objectAtIndex:i] == arrItems.count){
[strItemList appendString:[NSString stringWithFormat:#"%#", [[arrItems objectAtIndex:i]objectForKey:#"ItemList"]]];
}
else {
[strItemList appendString:[NSString stringWithFormat:#"%#,", [[arrItems objectAtIndex:i]objectForKey:#"ItemList"]]];
}
Assuming that arrItems is an NSArray with elements #"iPhone", #"iPad", and #"iPod", you can do this:
NSArray *list = [arrItems componentsJoinedByString:#","]
NSArray with elements #"iPhone", #"iPad", and #"iPod"
NSString *str=[[arrItems objectAtIndex:0]objectForKey:#"ItemList"]]
str = [str stringByAppendingFormat:#",%#",[[arrItems objectAtIndex:1]objectForKey:#"ItemList"]]];
str = [str stringByAppendingFormat:#",%#",[[arrItems objectAtIndex:2]objectForKey:#"ItemList"]]];
NsLog(#"%#",str);
// Assuming...
NSDictionary *dictionary1 = [NSDictionary dictionaryWithObject:[NSArray arrayWithObjects:#"iPhone", #"iPodTouch", nil] forKey:#"ItemList"];
NSDictionary *dictionary2 = [NSDictionary dictionaryWithObject:[NSArray arrayWithObjects:#"iPad", #"iPad2", #"Apple TV", nil] forKey:#"ItemList"];
NSDictionary *dictionary3 = [NSDictionary dictionaryWithObject:[NSArray arrayWithObjects:#"iMac", #"MacBook Pro", #"Mac Pro", nil] forKey:#"ItemList"];
NSArray *arrItems = [NSArray arrayWithObjects:dictionary1, dictionary2, dictionary3, nil];
// create string list
NSString *strItemList = [[arrItems valueForKeyPath:#"#unionOfArrays.ItemList"] componentsJoinedByString:#", "];
NSLog(#"All Items List: %#", strItemList);
Output:
All Items List: iPhone, iPodTouch, iPad, iPad2, Apple TV, iMac, MacBook Pro, Mac Pro
This method will return you the nsmutablestring with comma separated values from an array
-(NSMutableString *)strMutableFromArray:(NSMutableArray *)arr withSeperater:(NSString *)saperator
{
NSMutableString *strResult = [NSMutableString string];
for (int j=0; j<[arr count]; j++)
{
NSString *strBar = [arr objectAtIndex:j];
[strResult appendString:[NSString stringWithFormat:#"%#",strBar]];
if (j != [arr count]-1)
{
[strResult appendString:[NSString stringWithFormat:#"%#",seperator]];
}
}
return strResult;
}

NSString to NSArray

I want to split an NSString into an NSArray. For example, given:
NSString *myString=#"ABCDEF";
I want an NSArray like:
NSArray *myArray={A,B,C,D,E,F};
How to do this with Objective-C and Cocoa?
NSMutableArray *letterArray = [NSMutableArray array];
NSString *letters = #"ABCDEF𝍱क्";
[letters enumerateSubstringsInRange:NSMakeRange(0, [letters length])
options:(NSStringEnumerationByComposedCharacterSequences)
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[letterArray addObject:substring];
}];
for (NSString *i in letterArray){
NSLog(#"%#",i);
}
results in
A
B
C
D
E
F
𝍱
क्
enumerateSubstringsInRange:options:usingBlock: available for iOS 4+ can enumerate a string with different styles. One is called NSStringEnumerationByComposedCharacterSequences, what will enumerate letter by letter but is sensitive to surrogate pairs, base characters plus combining marks, Hangul jamo, and Indic consonant clusters, all referred as Composed Character
Note, that the accepted answer "swallows" 𝍱and breaks क् into क and ्.
Conversion
NSString * string = #"A B C D E F";
NSArray * array = [string componentsSeparatedByString:#" "];
//Notice that in this case I separated the objects by a space because that's the way they are separated in the string
Logging
NSLog(#"%#", array);
This is what the console returned
NSMutableArray *chars = [[NSMutableArray alloc] initWithCapacity:[theString length]];
for (int i=0; i < [theString length]; i++) {
NSString *ichar = [NSString stringWithFormat:#"%C", [theString characterAtIndex:i]];
[chars addObject:ichar];
}
This link contains examples to split a string into a array based on sub strings and also based on strings in a character set. I hope that post may help you.
here is the code snip
NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[myString length]];
for (int i=0; i < [myString length]; i++) {
NSString *ichar = [NSString stringWithFormat:#"%c", [myString characterAtIndex:i]];
[characters addObject:ichar];
}
Without loop you can use this:
NSString *myString = #"ABCDEF";
NSMutableString *tempStr =[[NSMutableString alloc] initWithString:myString];
if([myString length] != 0)
{
NSError *error = NULL;
// declare regular expression object
NSRegularExpression *regex =[NSRegularExpression regularExpressionWithPattern:#"(.)" options:NSMatchingReportCompletion error:&error];
// replace each match with matches character + <space> e.g. 'A' with 'A '
[regex replaceMatchesInString:tempStr options:NSMatchingReportCompletion range:NSMakeRange(0,[myString length]) withTemplate:#"$0 "];
// trim last <space> character
[tempStr replaceCharactersInRange:NSMakeRange([tempStr length] - 1, 1) withString:#""];
// split into array
NSArray * arr = [tempStr componentsSeparatedByString:#" "];
// print
NSLog(#"%#",arr);
}
This solution append space in front of each character with the help of regular expression and uses componentsSeparatedByString with <space> to return an array
Swift 4.2:
String to Array
let list = "Karin, Carrie, David"
let listItems = list.components(separatedBy: ", ")
Output : ["Karin", "Carrie", "David"]
Array to String
let list = ["Karin", "Carrie", "David"]
let listStr = list.joined(separator: ", ")
Output : "Karin, Carrie, David"
In Swift, this becomes very simple.
Swift 3:
myString.characters.map { String($0) }
Swift 4:
myString.map { String($0) }

Split one string into different strings

i have the text in a string as shown below
011597464952,01521545545,454545474,454545444|Hello this is were the message is.
Basically i would like each of the numbers in different strings to the message eg
NSString *Number1 = 011597464952
NSString *Number2 = 01521545545
etc
etc
NSString *Message = Hello this is were the message is.
i would like to have that split out from one string that contains it all
I would use -[NSString componentsSeparatedByString]:
NSString *str = #"011597464952,01521545545,454545474,454545444|Hello this is were the message is.";
NSArray *firstSplit = [str componentsSeparatedByString:#"|"];
NSAssert(firstSplit.count == 2, #"Oops! Parsed string had more than one |, no message or no numbers.");
NSString *msg = [firstSplit lastObject];
NSArray *numbers = [[firstSplit objectAtIndex:0] componentsSepratedByString:#","];
// print out the numbers (as strings)
for(NSString *currentNumberString in numbers) {
NSLog(#"Number: %#", currentNumberString);
}
Look at NSString componentsSeparatedByString or one of the similar APIs.
If this is a known fixed set of results, you can then take the resulting array and use it something like:
NSString *number1 = [array objectAtIndex:0];
NSString *number2 = [array objectAtIndex:1];
...
If it is variable, look at the NSArray APIs and the objectEnumerator option.
NSMutableArray *strings = [[#"011597464952,01521545545,454545474,454545444|Hello this is were the message is." componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#",|"]] mutableCopy];
NString *message = [[strings lastObject] copy];
[strings removeLastObject];
// strings now contains just the number strings
// do what you need to do strings and message
....
[strings release];
[message release];
does objective-c have strtok()?
The strtok function splits a string into substrings based on a set of delimiters.
Each subsequent call gives the next substring.
substr = strtok(original, ",|");
while (substr!=NULL)
{
output[i++]=substr;
substr=strtok(NULL, ",|")
}
Here's a handy function I use:
///Return an ARRAY containing the exploded chunk of strings
///#author: khayrattee
///#uri: http://7php.com
+(NSArray*)explodeString:(NSString*)stringToBeExploded WithDelimiter:(NSString*)delimiter
{
return [stringToBeExploded componentsSeparatedByString: delimiter];
}