How to Do Indexofobject or a Proper Containsobject

How do I do indexOfObject or a proper containsObject

You can use the built-in find, and thus avoid bridging to Objective-C — but only if your element type is Equatable. (If it isn't Equatable, you can make it so with a comparison function and an extension.)

Example:

func == (lhs:Piece,rhs:Piece) -> Bool {
return lhs.val == rhs.val
}

class Piece:Equatable,Printable {
var val : Int
var description : String { return String(val) }
init (_ v:Int) {
val = v
}
}

Now you can call find(arr,p) where arr is an Array<Piece> and p is a Piece.

Once you have this, you can develop utilities based on it. For example, here's a global function to remove an object from an array without bridging to Objective-C:

func removeObject<T:Equatable>(inout arr:Array<T>, object:T) -> T? {
if let found = find(arr,object) {
return arr.removeAtIndex(found)
}
return nil
}

And test it like this:

var arr = [Piece(1), Piece(2), Piece(3)]
removeObject(&arr,Piece(2))
println(arr)

You can do this for NSObject subclasses too. Example:

func == (v1:UIView, v2:UIView) -> Bool {
return v1.isEqual(v2)
}
extension UIView : Equatable {}

Now you can call find on an Array of UIView. It's sort of a pain in the butt, though, having to do this for every single class where you want to be able to use find on an Array of that class. I have filed an enhancement request with Apple requesting that all NSObject subclasses be considered Equatable and that == should fall back on isEqual: automatically.

EDIT Starting in Seed 3, this is automatic for UIView and other NSObject classes. So find now just works for them.

EDIT 2 Starting in Swift 2.0, indexOf will exist as a method:

let s = ["Manny", "Moe", "Jack"]
let ix = s.indexOf("Moe") // 1

Alternatively, it takes a function that returns Bool:

let ix2 = s.indexOf {$0.hasPrefix("J")} // 2

Again, this works only on collections of Equatable, since obviously you cannot locate a needle in a haystack unless you have a way of identifying a needle when you come to it.

EDIT 3 Swift 2.0 also introduces protocol extensions. This means I can rewrite my global function removeObject as a method!

For example:

extension RangeReplaceableCollectionType where Generator.Element : Equatable {
mutating func removeObject(object:Self.Generator.Element) {
if let found = self.indexOf(object) {
self.removeAtIndex(found)
}
}
}

Since Array adopts RangeReplaceableCollectionType, now I can write code like this:

var arr = [Piece(1), Piece(2), Piece(3)]
arr.removeObject(Piece(2))

Oh, happy day!

How to get indices of NSArray using something like indexOfObject?

To get multiple indices, you can use indexesOfObjectsPassingTest::

// a single element to search for
id target;
// multiple elements to search for
NSArray *targets;
...
// every index of the repeating element 'target'
NSIndexSet *targetIndices = [array indexesOfObjectsPassingTest:^ BOOL (id obj, NSUInteger idx, BOOL *stop) {
return [obj isEqual:target];
}];

// every index of every element of 'targets'
NSIndexSet *targetsIndices = [array indexesOfObjectsPassingTest:^ BOOL (id obj, NSUInteger idx, BOOL *stop) {
return [targets containsObject:obj];
}];

Support for blocks were added in iOS 4. If you need to support earlier versions of iOS, indexesOfObjectsPassingTest: isn't an option. Instead, you can use indexOfObject:inRange: to roll your own method:

@interface NSArray (indexesOfObject)
-(NSIndexSet *)indexesOfObject:(id)target;
@end

@implementation NSArray (indexesOfObject)
-(NSIndexSet *)indexesOfObject:(id)target {
NSRange range = NSMakeRange(0, [self count]);
NSMutableIndexSet *indexes = [[NSMutableIndexSet alloc] init];
NSUInteger idx;
while (range.length && NSNotFound != (idx = [self indexOfObject:target inRange:range])) {
[indexes addIndex: idx];
range.length -= idx + 1 - range.location;
range.location = idx + 1;
}
return [indexes autorelease];
}
@end

NSMutableArray check object at specific index

Checking if an array "contains" an item at a specific index just sounds like a fancy way of stating the general case of accessing any item from an array at a given index, no?

if ([[theQueueArray objectAtIndex:0] isEqual:elementName]) {
// ...
}

(If this isn't what you mean, consider clarifying the question.)

Check if something exists in an NSMutableArray

No check simply using :

[myArray indexOfObject:myObject];

or

[myArray containsObject:myObject];

These methods check every object using isEqual.


For example:

NSUInteger objIdx = [myArray indexOfObject: myObject];
if(objIdx != NSNotFound) {
id myObj = [myArray objectAtIndex: objIdx];
// Do some alter stuff here
}

NSArray containsObject: faster alternative?

If you NEED to use an array, skip a bit further down


Alternate Options

Your other options might include:

  • Using an NSDictionary which uses key->value pairs which (I expect will) have O(1) read complexity at the cost of extra storage space for the keys

  • If you aren't using duplicates and order isn't important, using an NSSet will offer better read complexity (I don't know what the complexity will be, the docs probably will)


Using an Array

If you keep the array sorted, searching can be done in O(log n) time instead of O(n) as you can take advantage of a binary search.

Caveat Lector: This was written from memory

-(void) /*adding*/
{
int proposedIndex = 0;
proposedIndex = [array indexOfObject:node
inSortedRange:NSMakeRange(0, array.count)
options:NSBinarySearchingInsertionIndex
usingComparator:
^ NSComparisonResult(id obj1, id obj2)
{
if (obj1.valueToCompare < obj2.valueToCompare) return NSOrderedAscending;
if (obj1.valueToCompare > obj2.valueToCompare) return NSOrderedDescending;
else return NSOrderedSame;
}];

[array insertObject:node atIndex:proposedIndex];
}

-(id) /* Getting */
{
int location = [array indexOfObject:node
inSortedRange:NSMakeRange(0, array.count)
options:NSBinarySearchingFirstEqual
usingComparator:
^ NSComparisonResult(id obj1, id obj2)
{
if (obj1.valueToCompare < obj2.valueToCompare) return NSOrderedAscending;
if (obj1.valueToCompare > obj2.valueToCompare) return NSOrderedDescending;
else return NSOrderedSame;
}];
if (location == NSNotFound) return nil;
return [array objectAtIndex:location];
}

Extending a Swift Array to replicate indexOfObject function

protocol Identifiable {
@infix func ===(a: Self, b: Self) -> Bool
}

struct Item : Identifiable {
var n : Int
}

@infix func ===(a: Item, b: Item) -> Bool {
return a.n == b.n
}
var _privateItems = [Item(n:1),Item(n:2),Item(n:2),Item(n:1),Item(n:2)]
func removeItem(item: Item) {
var tbr : Int[] = []
for (index, element) in enumerate(_privateItems) {
if element === item {
tbr += index
}
}
for i in reverse(sort(tbr)) {
_privateItems.removeAtIndex(i)
}
}
removeItem(Item(n:2))

println(_privateItems.count)
removeItem(Item(n:1))
println(_privateItems.count)


Related Topics



Leave a reply



Submit