Count number of times object appears in NSArray - ios

I have an NSArray of 5 dice (dice1, dice2, dice3...). Once I have run the random number generator each dice1, dice2, dice3... can return a value between 1-6.
I would like to be able to count how many times a value of 1-6 has been returned.
I'm not too sure of the best way, whether I should turn the int number 1-6 into a string to match.

This is one of those situations where I don't feel that there is a particularly elegant solution due to the inability of Foundation types (such as NSCountedSet) to store intrinsic types (such as int). Swift's automatic boxing/unboxing of ints into NSNumber is a nice feature in this sort of situation.
Since you dealing with a small number of dice and a small number of possible values then you could ignore objects, sets and all that and just loop over your dice array, updating an array of integer counts.
The other, more complex, but object-oriented approach is to create a Die class:
Die.h
#import <Foundation/Foundation.h>
#interface Die : NSObject
-(instancetype)initWithSides:(NSUInteger)sides;
-(instancetype)initWithSides:(NSUInteger)sides initialValue:(NSUInteger)value;
-(NSUInteger)value;
-(NSUInteger)roll;
-(NSUInteger)sides;
#end
Die.m
#import "Die.h"
#interface Die ()
#property NSUInteger currentValue;
#property NSUInteger numberOfsides;
#end
#implementation Die
- (instancetype)initWithSides:(NSUInteger)sides {
NSAssert(sides>1, #"Dice must have at least 2 sides");
if (self = [super init]) {
self.numberOfsides = sides;
[self roll];
}
return self;
}
- (instancetype)initWithSides:(NSUInteger)sides initialValue:(NSUInteger)value {
NSAssert(sides>1, #"Dice must have at least 2 sides");
NSAssert(value <= sides, #"Initial value must not exceed number of sides");
if (self = [super init]) {
self.numberOfsides = sides;
self.currentValue = value;
}
return self;
}
- (NSUInteger)roll {
self.currentValue = arc4random_uniform((UInt32)self.numberOfsides)+1;
return self.currentValue;
}
- (NSUInteger)value {
return self.currentValue;
}
- (NSUInteger)sides {
return self.numberOfsides;
}
- (NSUInteger)hash {
return self.currentValue;
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[Die class]]) {
return NO;
}
return [self isEqualToDie:(Die *)object];
}
- (BOOL) isEqualToDie:(Die *)otherDie {
return self.currentValue == otherDie.value;
}
#end
So now you have an object that can be stored in an NSCountedSet and you can retrieve the counts. This bit is slightly awkward since you need to compare to a Die with the appropriate value, not just the value itself:
// self.dice is an array of `Die` objects
NSCountedSet *valueCounts = [NSCountedSet setWithArray:self.dice];
for (int i=1;i<7;i++) {
NSUInteger count = [valueCounts countForObject:[[Die alloc] initWithSides:6 initialValue:i]];
NSLog(#"There are %lu dice showing %d",count,i);
}

use dictionaries :
let arrNum = [“one”, “two”, “three”, “two”]
var countNumber:[String:Int] = [:]
for item in arrNum {
countNumber[item] = (countNumber[item] ?? 0) + 1
}
for (key, value) in countNumber {
print("\(key) occurs \(value) time")
}
o/p :
one occurs 1 time
two occurs 2 time
three occurs 1 time

Related

Random number that doesn't repeat twice in a row [duplicate]

This question already has answers here:
Non repeating random numbers in Objective-C
(6 answers)
Closed 7 years ago.
I'm pretty new to coding, I've been looking for similar questions but none fits my needs. I'm working in a dice rolling app, and I need a a random number generator to "roll" the dice. arc4random seems perfect, but the problems that I can't have the same face occurring twice in a row. I have a method firing when I press the button with a timer
- (IBAction)dieRoll:(id)sender {
self.currentFace = 1;
_timer = [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:#selector(roll) userInfo:nil repeats:YES];;
}
but I have to implement the 'roll' method where I get a random number different from the one already selected (the property self.currentFace).
any clue?
this is how your implementation could look like:
#interface ViewController ()
#property (assign, nonatomic) NSInteger currentFace;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.currentFace = -1;
}
- (IBAction)diceRoll:(id)sender {
NSInteger newFace = -1;
do {
newFace = arc4random_uniform(6) + 1;
} while (newFace == self.currentFace);
self.currentFace = newFace;
}
#end
A simple solution would be to just remember the last rolled number and roll the dice until you get a different one. Pretty simple and you can keep arc4random.
An example:
- (NSUInteger)rollDiceWithLastFaceNumber:(NSUInteger)lastFaceNumber
{
NSUInteger currentFaceNumber;
do {
currentFaceNumber = (arc4random_uniform(6) + 1);
} while (currentFaceNumber == lastFaceNumber);
return currentFaceNumber;
}
and how to use it:
[self rollDiceWithLastFaceNumber:3];
This solution avoids an unknown number of iterations until you get your result.
- (void)roll {
NSUInteger next = [self nextFaceWithPreviousFace:self.currentFace];
NSLog(#"%lu", next);
self.currentFace = next;
}
- (NSUInteger)nextFaceWithPreviousFace:(NSUInteger)previous {
NSMutableArray *candidates = [NSMutableArray arrayWithObjects:#1, #2, #3, #4, #5, #6, nil];
[candidates removeObject:#(previous)];
NSUInteger index = arc4random_uniform((unsigned)candidates.count);
return [candidates[index] unsignedIntegerValue];
}

Can't change "int" in Objective C

I have had a very weird experience with Objective C and xCode these last couple of days. I'm now turning to you guys for some quick help.
I'm simply trying to set up and int, call in damage(the amount of damage this object is supposed to do) and increase it if a void function is called.
-(void) increaseDagage{
damage = damage + 100;
NSLog(#"%f", damage);
}
I have tried setting the int damage up as a int and also as
#property (nonatomic, assign) float damage;
The problem is that when I print "damage" it hasn't increased...
I also have a function that returns the amount of damage this object does and it returns the wrong value.
I can't figure out why this isn't doing what I want...
I also have an int called health, which is basically the same thing and works fine.
Here's the full class if you want to see that too,
//
// Character.m
// TD
//
// Created by Victor Appelgren on 2014-12-23.
// Copyright (c) 2014 Victor Appelgren. All rights reserved.
//
#import "Character.h"
#import "constants.h"
#import "Level.h"
#import "GameViewController.h"
#interface Character (){
SKSpriteNode *character;
float health;
float maxHealth;
Level *level;
GameViewController *gVC;
BOOL dead;
int damage;
}
//#property (nonatomic, assign) float damage;
#end
#implementation Character
-(id) init {
if (self = [super init]){
damage = 100;
dead = NO;
// Load health
maxHealth = 200;
health = 200.0;
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:character.frame.size.width / 2];
[self addChild:character];
}
return self;
}
-(void) doDamageType:(int)type{ // here a type is passed in to tell how much damage is being done.
if (type == 1){
health = health - 20;
} else if (type == 2){
health = health - 40;
}
if (health <= 0){
[self removeFromParent];
dead = YES;
}
}
-(void) increaseDagage{
damage = damage + 100.0;
// NSLog(#"%f", _damage);
}
-(int) returnDamage{
return damage;
}
-(BOOL) returnDead{
return dead;
}
-(float) returnHealth{
return health;
}
-(float) returnMaxHealth{
return maxHealth;
}
#end
Here's the output I'm getting,
2015-02-22 01:28:27.722 TD[279:43180] 200.000000
2015-02-22 01:28:30.327 TD[279:43180] 200
2015-02-22 01:28:30.496 TD[279:43180] 200
2015-02-22 01:28:30.644 TD[279:43180] 200
2015-02-22 01:28:30.809 TD[279:43180] 200
first is initial value and the rest is from when the function is being called
What is wrong....
I might be missing something here but can't seem to find the problem
Thanks for the help
The problem is that you've created two different damage variables -- one in your .h and another in your .m. The one in your .h is public and accessible from your .m using self.damage. The one you've declared in your .m is private and accessible simply using damage. So the problem here is that you're accessing the public version of your damage from the other class, but you're actually manipulating the private version within your class.
So I'd recommend changing the following methods and property declarations of your .m as follows:
// ***Remove the private declaration of damage***
#interface Character (){
SKSpriteNode *character;
float health;
float maxHealth;
Level *level;
GameViewController *gVC;
BOOL dead;
}
#end
#implementation Character
// ***And add "self." before each instance of damage***
-(id) init {
if (self = [super init]){
self.damage = 100;
dead = NO;
// Load health
maxHealth = 200;
health = 200.0;
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:character.frame.size.width / 2];
[self addChild:character];
}
return self;
}
-(void) increaseDagage{
self.damage = self.damage + 100.0;
// NSLog(#"%f", self.damage);
}
-(int) returnDamage{
return self.damage;
}
#end
You have a spelling error in your method name : increaseDagage
I am guessing this should be increaseDamage
You also seem to be creating your own setters and getters. I would read up on the usage of properties.
Several things jump out:
Your method is called increaseDagage. Do you get any error message in Xcode's console when you call it?
You are not telling us whether you are getting any error or warning messages from the code. You should be getting some.
You keep talking about ints, but the log statement and property you define are floats.
You are not #synthesizeing your float damage property. So that means that it will create its own _damage instance variable to store the value and not use your damage instance variable (which would be the wrong type anyway).
You are logging _damage, not damage.
In short, the code, as written, mixes up two completely different things.

Intersecting two NSArrays with non-comparable objects inside

The following code receives an array of events from EventKit for the selected day, then "pads" the existing calendar events with empty events to fill hourly slots from the entire day (9-5, for example).
The events coming from the iOS calendar are contained within a custom event container class that I created. The event class has the following properties:
// HDEvent.h
#interface HDEvent : NSObject
#property(nonatomic, copy) NSDate *startDate;
#property(nonatomic, copy) NSDate *endDate;
#property(nonatomic, strong) EKEvent *event;
#property(nonatomic, copy) NSString *eventIdentifier;
#property(nonatomic, copy) NSString *tempTitle;
#end
I am attempting to replace the empty events with any true events from the calendar, based on the start/end dates of the HDEvent object. The incoming array for the following method has the events (if any) from the device calendar.
- (NSArray *)addEmptyEventsWithEvents:(NSMutableArray *)events
ForDate:(NSDate *)date {
NSMutableOrderedSet *finalEvents = [[NSMutableOrderedSet alloc] init];
// this returns an array filled with the empty HDEvents
// for the expected date range.
NSArray *emptyEvents = [self getEventsTimeRangeFromDate:date];
for (HDEvent *emptyEvent in emptyEvents) {
HDEvent *eventToAdd;
for (HDEvent *event in events) {
NSLog(#"Event: %#", event.event.title);
if ([event.startDate isEqualToDate:emptyEvent.startDate] ||
[event.endDate isEqualToDate:emptyEvent.endDate])
{
eventToAdd = event;
} else {
eventToAdd = emptyEvent;
}
}
[finalEvents addObject:eventToAdd];
}
return [finalEvents array];
}
I am attempting to create an array with my events as illustrated in the pseudo-code below:
// Calendar Events
[
10:00-11:00 MEETING,
11:00-12:00 LUNCH
]
// Empty Placeholders
[
09:00-10:00 EMPTY,
10:00-11:00 EMPTY,
11:00-12:00 EMPTY,
12:00-01:00 EMPTY,
01:00-02:00 EMPTY,
02:00-03:00 EMPTY,
03:00-04:00 EMPTY,
04:00-05:00 EMPTY,
]
// Final desired result:
[
09:00-10:00 EMPTY,
10:00-11:00 MEETING,
11:00-12:00 LUNCH,
12:00-01:00 EMPTY,
01:00-02:00 EMPTY,
02:00-03:00 EMPTY,
03:00-04:00 EMPTY,
04:00-05:00 EMPTY,
]
[Problem]:
The problem is that the array returned only contains one event from the calendar (though I can see in the NSLog response that I have two events on that day)
If I swap the for loops around, then I get 9 events (again, only one from the calendar, and one duplicate empty event.)
Thank you #vikingosegundo.
I ended up implementing a custom comparison method in my class following the advice contained in this answer here: https://stackoverflow.com/a/877881/810360
I also extended it to be more flexible by utilizing the excellent DateTools by Matthew York found on GitHub: https://github.com/MatthewYork/DateTools
This was my final code:
-(BOOL)isEqualToEvent:(HDEvent*)event {
if (self == event) {
return YES;
}
if ([event.startDate isEqualToDate:self.startDate] &&
[event.endDate isEqualToDate:self.endDate]) {
return YES;
} else {
return NO;
}
}
-(BOOL)doesEventIntersectEvent:(HDEvent*)event {
DTTimePeriod *eventTimePeriod = [DTTimePeriod timePeriodWithStartDate:event.startDate endDate:event.endDate];
DTTimePeriod *selfTimePeriod = [DTTimePeriod timePeriodWithStartDate:self.startDate endDate:self.endDate];
if ([eventTimePeriod intersects:selfTimePeriod]) {
return YES;
} else {
return NO;
}
}
-(BOOL)doesEventContainEvent:(HDEvent*)event {
DTTimePeriod *eventTimePeriod = [DTTimePeriod timePeriodWithStartDate:event.startDate endDate:event.endDate];
DTTimePeriod *selfTimePeriod = [DTTimePeriod timePeriodWithStartDate:self.startDate endDate:self.endDate];
if ([eventTimePeriod contains:selfTimePeriod]) {
return YES;
} else {
return NO;
}
}

Double pointers with Objective-C. Change where a pointer points to.

I have a UITableView where I have two data sources.
#property(strong)NSArray* mediaItems;
#property(strong)NSArray* likesItems;
In a lot of cases I need to swap both of the sources out. As a result there is a lot of if statements where I check
if (self.activePage == kDrawingsPage) self.mediaItems = responseObject;
else self.likesItems = responseObject;
What I would like to do is not need to keep checking like this. Using a double pointer. Could I not use a double pointer to do something like. (this does not work)
NSArray** activeItems = &self.mediaItems;
Then in places where I need to access the data I can simply do
- (NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section {
NSArray* arr = *self.activeItems;
return [arr count];
}
Instead of
- (NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section {
if (self.activePage == kDrawingsPage) [self.mediaItems count];
else [self.likesItems count];
}
Shouldn't a double pointer or something similar work in this case? If it cannot work what other way can I minimize these if statements.
You can use computed property
in #interface
#property (readonly) NSArray* activeItems;
in #implementation
- (NSArray *)activeItems {
return self.activePage == kDrawingsPage ? self.mediaItems : self.likesItems
}
so you can do
- (NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.activeItems count];
}
&self.mediaItems won't give you any meaningful value, because it is same as &[self mediaItems], which give you the address of a returned temporary object.
It should be &_mediaItems i.e. the address of the underlying ivar.

NSMutableArray thread safety

In my app I'm accessing and changing a mutable array from multiple threads. At the beginning it was crashing when I was trying to access an object with objectAtIndex, because index was out of bounds (object at that index has already been removed from array in another thread). I searched on the internet how to solve this problem, and I decided to try this solution .I made a class with NSMutableArray property, see the following code:
#interface SynchronizedArray()
#property (retain, atomic) NSMutableArray *array;
#end
#implementation SynchronizedArray
- (id)init
{
self = [super init];
if (self)
{
_array = [[NSMutableArray alloc] init];
}
return self;
}
-(id)objectAtIndex:(NSUInteger)index
{
#synchronized(_array)
{
return [_array objectAtIndex:index];
}
}
-(void)removeObject:(id)object
{
#synchronized(_array)
{
[_array removeObject:object];
}
}
-(void)removeObjectAtIndex:(NSUInteger)index
{
#synchronized(_array)
{
[_array removeObjectAtIndex:index];
}
}
-(void)addObject:(id)object
{
#synchronized(_array)
{
[_array addObject:object];
}
}
- (NSUInteger)count
{
#synchronized(_array)
{
return [_array count];
}
}
-(void)removeAllObjects
{
#synchronized(_array)
{
[_array removeAllObjects];
}
}
-(id)copy
{
#synchronized(_array)
{
return [_array copy];
}
}
and I use this class instead of old mutable array, but the app is still crashing at this line: return [_array objectAtIndex:index]; I tried also this approach with NSLock, but without a luck. What I'm doing wrong and how to fix this?
I believe this solution is poor. Consider this:
thread #1 calls count and is told there are 4 objects in the array.
array is unsynchronized.
thread #2 calls removeObjectAtIndex:2 on the array.
array is unsynchronized.
thread #1 calls objectAtIndex:3 and the error occurs.
Instead you need a locking mechanism at a higher level where the lock is around the array at both steps 1 and 5 and thread #2 cannot remove an object in between these steps.
You need to protect (with #synchronized) basically all usage of the array. Currently you only prevent multiple threads from concurrently getting objects out of the array. But you have no protection for your described scenario of concurrent modification and mutation.
Ask yourself why you're modifying the array on multiple threads - should you do it that way or just use a single thread? It may be easier to use a different array implementation or to use a wrapper class that always switches to the main thread to make the requested modification.

Resources