[myItem enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (obj isEqualToString:#"someString" > 1) { // not correct syntax
self.someLabel.text = [self.someLabel.text stringByAppendingString:[NSString stringWithFormat:#"\t\t%#\n", obj]];
}
}];
I am trying to check if obj is equal to "someString". And if "someString" is displayed more than one I would like to remove it from the obj.
"itemOne"
"otherItem"
"someString"
"someString" <- remove
"someString" <- remove
I am having issues dynamically doing this within the loop in objective c.
An easier solution is to convert the array to an ordered set and then back to an array. This will remove duplicates.
try like this,
UniqArray = [CurrentArray valueForKeyPath:#"#distinctUnionOfObjects.self"];
or
NSArray *UniqArray = [[NSOrderedSet orderedSetWithArray:CurrentArray]allObjects];
or
NSArray *UniqArray = [[NSSet setWithArray:CurrentArray] allObjects]
You can convert it to an ordered set, which removes the duplicates, then convert it back to an array.
// remove duplicates
NSOrderedSet *myItemSet = [NSOrderedSet orderedSetWithArray:myItem];
// convert it back to NSArray
NSArray *myItemArrayWithoutDuplicates = myItemSet.array;
You can use continue statement for displaying the data without dublicates
[myItem enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isEqualToString:#"someString"]) {
self.someLabel.text = [self.someLabel.text stringByAppendingString:[NSString stringWithFormat:#"\t\t%#\n", obj]];
continue;
}
}];
This will exist from current iteration after value assigned in label.
If you want to delete the dublicate objects. If Order of Items does not matter...
NSArray *itemsArray = [[NSSet setWithArray: myItem] allObjects];
If order of items matter..
NSMutableArray *uniqueItems = [NSMutableArray array];
for (id item in myItem)
if (![uniqueItems containsObject:item])
[uniqueItems addObject:item];
Hope it helps you..
Swift 5
let array = ["itemOne", "otherItem", "someString", "someString", "someString"]
print(array) // "itemOne", "otherItem", "someString", "someString", "someString"]
var set = Set<String>()
for item in array{
set.insert(item)
}
print(set) // ["otherItem", "someString", "itemOne"]
Related
I am trying to tackle the following sorting and separating, I have an array with IDs like 1,2,3,4,5,3,2,1.
Sorting that array with NSPredicate is quite straightforward but how can i also separate same IDs in separate sub-arrays like [[1,1][2,2,],[3,3],[4],[5]]? I guess one option is to loop the sorted array and compare previous index ids, but I am wondering if any helper function exist in iOS, I am currently reading about NSOrderedSet but cant seem to find if it can help.
In Swift , with functional programming:
let indexes = [1,2,3,4,5,3,2,1]
let notRepeatedIndexesSet = Set(indexes)
let notRepeatedIndexesArray = Array(notRepeatedIndexesSet).sorted(<)
let yourArray = notRepeatedIndexesArray.map{
number -> [Int] in
Array(count: indexes.filter { $0 == number }.count, repeatedValue:number)
}
A combination of ordered and counted sets:
NSArray *array = #[#1,#2,#3,#4,#5,#3,#2,#1];
NSOrderedSet *os = [[NSOrderedSet alloc] initWithArray:array];
NSCountedSet *cs = [[NSCountedSet alloc] initWithArray:array];
NSMutableArray *sortedArray = [#[] mutableCopy];
[os enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSMutableArray *countArray = [#[] mutableCopy];
for (int i = 0; i < [cs countForObject:obj]; ++i) {
[countArray addObject:obj];
}
[sortedArray addObject:[countArray copy]];
}];
It's hard to explain why I need index of duplicate elements in array. When I tried to fetch the index of element in traditional way it shows only one index, but I need to fetch the all index of duplicate values
for ex:
NSArray *array=#[#"one",#"one",#"one",#"two",#"two",#"four",#"four",#"four"];
int index = [array indexOfObject:element];
NSLog(#"index %d",index);
here if I try to fetch index of " one " it shows index is 0 but I need to get further indexes of one
You can fetch the index of duplicates like this:
NSArray *array=#[#"one",#"one",#"one",#"two",#"two",#"four",#"four",#"four"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
if ([obj isEqualToString:#"one"])
{
NSLog(#"index %d",idx);
}
}];
int i,count=0;
for (i = 0; i < [array count]; i++) {
if element == [array objectAtIndex:i] {
indices[count++] = i;
}
}
Declare an empty array indices, and indices will contain all the indices of the given element.
NSString *element = #"one";
NSArray *array=#[#"one",#"one",#"one",#"two",#"two",#"four",#"four",#"four"];
NSIndexSet *matchingIndexes = [array indexesOfObjectsPassingTest:^BOOL(NSString *obj, NSUInteger idx, BOOL *stop) {
return [obj isEqual:element];
}];
[matchingIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSLog(#"%ld", (long)idx);
}];
Ultimately I don't think the NSArray methods are going to help you here, so you're going to have to write some pretty basic code. There is probably a cleaner answer, but here is a fairly simply solution to the problem.
This just goes through the array, and creates an NSDictionary for each unique number. It assumes the array is sorted as your example was, so simply checks the prior index's value against the current index to see if they have changed. When they change, it knows it's done with that value and saves the dictionary to an array.
NSArray *array=#[#"one",#"one",#"one",#"two",#"two",#"four",#"four",#"four"];
NSString *priorString = array[0];
NSMutableDictionary *duplicatesByKey = [[NSMutableDictionary alloc] init];
NSMutableArray *indexesOfDuplicates = [[NSMutableArray alloc] init];
int index = 0;
for (NSString *string in array) {
if ([priorString isEqualToString:string]) {
[indexesOfDuplicates addObject:[NSNumber numberWithInt:index]];
} else {
[duplicatesByKey setObject:indexesOfDuplicates forKey:priorString];
indexesOfDuplicates = [[NSMutableArray alloc] init];
[indexesOfDuplicates addObject:[NSNumber numberWithInt:index]];
}
priorString = string;
index ++;
}
[duplicatesByKey setObject:indexesOfDuplicates forKey:priorString];
I hope that helps.
Use
NSCountedSet * countedSet = [NSCountedSet setWithArray: array];
and
NSSet * uncountedSet = [NSSet setWithArray: array];
-- to create a counted set from your array, and a conventional NSSet.
Then:
[countedSet minusSet: uncountedSet];
countedSet will now contain only elements for the duplicates (if any), and the countForObject: method will return the number of duplicates (in excess of 1) for that element.
I have the following two arrays.
NSArray *array1=[[NSArray alloc]initWithObjects:#"ABC",#"DEF", nil];
NSArray *array2=[[NSArray alloc]initWithObjects:#"ABC",#"123",#"DEF",#"DEF", nil];
Now i have to search each array1's object and in array2 and need to get the matched indexes.
And my application contains more than one thousand objects in array2.
Please suggest the best possible way other than putting second for loop in first for loop
for (int i=0; i<array1.count; i++)
{
//Need to search the [array1 objectAtIndex:i] string in array2 and need to get the matched indexes into an array in best optimised way here.
NSMutableArray *matchedIndexesArray=[[NSMutableArray alloc]init];
NSString *stringToSearch=[array1 objectAtIndex:i];
//here i can put another array like below to get the matched indexes..but is there any optimized way other than this for loop here? or is there any simple inbuilt method to get the matched objects into an array here.
for (int j=0; j<array2.count; j++)
{
if ([stringToSearch isEqualToString:[array2 objectAtIndex:j]])
{
[matchedIndexesArray addObject:[NSString stringWithFormat:#"%d",j]];
}
}
NSLog(#"matchedIndexesArray-->%#<--",matchedIndexesArray);
//I will use this matchedIndexesArray here further processing...
//
//
//
//Large Code Here
//
//
//
}
According to the NSSet documentation, membership testing is faster for sets than for arrays.
Therefore it makes sense to convert array1 to a set first:
NSSet *set1 = [NSSet setWithArray:array1];
and then test each object of array2 for membership in the set. This can be conveniently
done as
NSIndexSet *matchingIndexes = [array2 indexesOfObjectsPassingTest:^BOOL(NSString *obj, NSUInteger idx, BOOL *stop) {
return [set1 containsObject:obj];
}];
Show all matching indexes:
[matchingIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSLog(#"%ld", (long)idx);
}];
// Output: 0, 2, 3
UPDATE: (after question edit) No, there is no method to fill an NSArray with the indices of matching objects. But there is a method to fill an NSIndexSet. NSIndexSet is a special collection to store indices
into some other data structure, such as an array. Then your code would look like
for (NSString *stringToSearch in array1) {
NSIndexSet *matchingIndexes = [array2 indexesOfObjectsPassingTest:^BOOL(NSString *obj, NSUInteger idx, BOOL *stop) {
return [stringToSearch isEqualToString:obj];
}];
NSLog(#"matchingIndexes: %#", matchingIndexes);
// Work with matchingIndex, for example enumerate all indices:
[matchingIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSLog(#"%ld", (long)idx);
}];
}
But I do not know if it makes much difference in performance.
NSArray *a = #[#"123", #"456", #"ABC", #"DEF"];
NSArray *b = #[#"123", #"ABC", #"---"];
NSIndexSet *indexes = [a indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop)
{
return [b containsObject:obj]
}];
NSLog(#"%#", indexes);
NSArray *array1=[[NSArray alloc]initWithObjects:#"ABC",#"DEF", nil];
NSArray *array2=[[NSArray alloc]initWithObjects:#"ABC",#"123",#"DEF",#"DEF", nil];
for (int i=0; i<array1.count; i++){
for (int j=0; j<array2.count; j++) {
if ([[array1 objectAtIndex:i] isEqualToString: [array2 objectAtIndex:j]]) {
NSLog(#"Matched Indexes %d %#", i, [array1 objectAtIndex:i] );
}
}
}
I currently have a NSArray which contains many NSArrays, each containing a pair of NSStrings such like the following: [["A", "B"], ["U", "A"], ["X", "Y"], ...], and I am interested first checking to see if it contains a particular object, and then grabbing the other paired object and putting it in an array. For example, if I am checking for "A" in the above array, the result array would contain ["B", "U"]
I know how to iterate over each array, but am trouble deciding how to grab the paired object inside the array... thanks!
for (NSArray *innerArray in outerArray){
if ([innerArray containsObject: #"A"]){
//how to extract the other object and save it to an array?
}
}
NSMutableArray *results = [NSMutableArray array];
for (NSArray *innerArray in outerArray){
// Get the index of the object we're looking for
NSUInteger index = [innerArray indexOfObject:#"A"];
if (index != NSNotFound) {
// Get the other index
NSUInteger otherIndex = index == 0 ? 1 : 0;
// Get the other object and add it to the array
NSString *otherString = [innerArray objectAtIndex:otherIndex];
[results addObject:otherString];
}
}
Should do the trick.
If you're sure that your data will have exactly the structure you describe, you can use the fact that inner array have exactly 2 element - so index of "other" element will be 1-indexOfYourElement:
for (NSArray *innerArray in outerArray){
NSUInteger ix = [innerArray indexOfObject:#"A"];
if (ix!=NSNotFound){
id objectToAdd = innerArray[1-ix];
// Do something with it
}
}
Here's one possible way:
NSMutableArray* results = [[NSMutableArray alloc] init];
for (NSArray *innerArray in outerArray){
if ([innerArray containsObject: #"A"]){
[results addObjectsFromArray: [innerArray enumerateObjectsUsingBlock:^(NSString* obj, NSUInteger idx, BOOL *stop) {
if (![obj isEqual: #"A"])
{
[results addObject: obj];
}
}]];
}
}
Value of my NSArray includes the duplicates.
I find the duplicates but now how can I find the no. they repeat?
You can use NSCountedSet for this. Add all your objects to a counted set, then use the countForObject: method to find out how often each object appears.
Example:
NSArray *names = [NSArray arrayWithObjects:#"John", #"Jane", #"John", nil];
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:names];
for (id item in set) {
NSLog(#"Name=%#, Count=%lu", item, (unsigned long)[set countForObject:item]);
}
You can try something like this
__block NSInteger elementCount = 0;
NSArray *array;
[<#NSArray yourArray#> indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop){
if (obj == <#yourObject#>) {
elementCount++;
return YES;
}
return NO;
}];
Let me know if that works for you