Xcode Count of like items in Array - arrays

I have a list of years in an Array. Which I would like to output as a list of the counts.
For example:
NSArray *years = #[#"2012", #"2014", #"2009", #"2014", #"2010", #"2014", #"2009"];
I am looking to turn this into something like this in a Dictionary.
Year = 2012, Count = 1
Year = 2014, Count = 3
Year = 2009, Count = 2
Year = 2010, Count = 1
Thanks

NSArray *years = [NSArray arrayWithObjects:#"2012", #"2014", #"2009", #"2014", #"2010", #"2014", #"2009", nil];
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:years];
for (id item in set)
{
NSLog(#"Name=%#, Count=%lu", item, (unsigned long)[set countForObject:item]);
}
I suggest you invest some time into reading a book about Cocoa's features.

Related

Local variable referenced before

I have an array of data which in the first column has years, and the other 3 columns has data for 3 different groups, the last of which is carrots.
I am trying to find the year in which the carrot value is the highest, by comparing the carrot value each year to the current highest, and then finding the year that the value takes place on.
I have used identical code for the other 2 columns with just the word carrot replaced and i in year[i] changed appropriately and the code works, but for this it throws up the error "local variable 'carrot_maxyear' referenced before assignment"
def carrot(data):
year0 = data[0]
carrotmax = year0[3]
for year in data:
if year[3] > carrotmax:
carrotmax = year[3]
carrot_maxyear = year[0]
return carrot_maxyear
Python's builtin max will make this easier:
def carrot(data):
maxyear = max(data, key=lambda year: year[3])
return maxyear[0]
This way you don't need the year0 and carrotmax initialization. We need to use the key argument to max because it looks like you want to return year[0] instead of the year[3] value used for the max calculation.
Your original version with a fix would look like:
def carrot(data):
year0 = data[0]
carrotmax = year0[3]
carrot_maxyear = 0 # initialize carrot_maxyear outside of loop to avoid error
for year in data:
if year[3] > carrotmax:
carrotmax = year[3]
carrot_maxyear = year[0]
return carrot_maxyear
but IMO the version utilizing max is more clear and Pythonic.

How to Access `NSArray` elements

I have a array like this
`
(lldb) po list
(NSArray *) $1 = 0x0759f120 <__NSArrayI 0x759f120>(
{
EmployeeCode = 7593;
InDate = "27/02/2013";
InTime = "08:11";
InTime2 = "00:00";
OutDate = "27/02/2013";
OutDate2 = "01/01/1901";
OutTime = "17:42";
OutTime2 = "00:00";
Present = 1;
}
)
`
How can I access each an individual elements in here. Plz help me
Thanks
Your NSArray contains values in NSDictionary format, so at each index within array you'll get a NSDictionary, so you can access it like this,
NSLog(#"Employee Code = %#", [[yourArray objectAtIndex:index] valueForKey:#"EmployeeCode"]);
where, index = 0 & index < [yourArray count]

Another NSDateFormatter issue

Having gone through the documentation, it would seem the following case should work, but the result is always nil. (This is for iOS sdk 6)
NSString *releaseDate = #"2012-10-22T00:00:00-07:00";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSDate *date = nil;
[dateFormatter setDateFormat:#"yyyy-MM-ddTHH:mm:ss-ZZZZZ"];
date = [dateFormatter dateFromString:releaseDate];
NSLog(#"Result date: %#", date); // Logs "(null)"
Any insights?
Thanks in advance for any help.
How about you try this. If your date string is unlocalized as I am guessing, even Apple suggests you could use something like this:
struct tm tmDate;
const char *formatString = "%Y-%m-%dT%H:%M:%S%z";
strptime_l(releaseDate, formatString, & tmDate, NULL);
date = [NSDate dateWithTimeIntervalSince1970: mktime(& tmDate)];
NSLog(#"Result date: %#", date);
Your release date will have to be a C string though, as in const char *releaseDate = "2012-10-22T00:00:00-07:00";, which you can get also from the UTF8String method of NSString.
Ok. A bit of re-reading of the docs revealed my misunderstandings:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSString *releaseDate = #"2012-10-22T00:00:00-07:00";
NSDate *date = nil;
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
date = [dateFormatter dateFromString:releaseDate];
NSLog(#"Result date: %#", date);
NSLog(#"Result string: %#", [dateFormatter stringFromDate:date]);
The "T" had to be enclosed in apostrophes and the "ZZZZZ" for time zone already accounts for the "-" so it had to be removed.
Now it works as expected.

predicateForEventsWithStartDate:endDate:calendars: EKEventStore doesn't work

i have saved 28 EKEvent in a EKCalendar in this range date: 2012-01-01 and 2013-01-18, the EKEvent are all stored and i can see it in the iOS Calendar on iCloud, then i want retrieve all this EKEvent in the range 2012-01-01 and 2013-01-18 and i use this method of EKEventStore:
predicateForEventsWithStartDate:endDate:calendars:
that is a NSPredicate to fetch event in the calendar, i pass with start date 2012-01-01 and with endDate:2013-01-18 so the array that return me with the EKEvent have only 8 element, so my question is why it doesn't find me all 28 event? what i wrong?
EDIT:
this is the complete code i use:
NSDate* sourceDate2 = [dateFormat dateFromString:#"2012/01/01"];
NSTimeZone* sourceTimeZone2 = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
NSTimeZone* destinationTimeZone2 = [NSTimeZone systemTimeZone];
NSInteger sourceGMTOffset2 = [sourceTimeZone2 secondsFromGMTForDate:sourceDate2];
NSInteger destinationGMTOffset2 = [destinationTimeZone2 secondsFromGMTForDate:sourceDate2];
NSTimeInterval interval2 = destinationGMTOffset2 - sourceGMTOffset2;
NSDate* destinationDate2 = [[NSDate alloc] initWithTimeInterval:interval2 sinceDate:sourceDate2];
NSTimeInterval time2 = floor([destinationDate2 timeIntervalSinceReferenceDate] / 86400.0) * 86400.0;
NSDate *startDate = [NSDate dateWithTimeIntervalSinceReferenceDate:time2];
then i use the same code for create the 2013-01-18 date that is the endDate, then i do this:
EKEventStore *eventStore = [[EKEventStore alloc] init];
NSPredicate *predicateEvent = [eventStore predicateForEventsWithStartDate:startDate endDate:endDate calendars:[eventStore calendarsForEntityType:EKEntityTypeEvent]];
NSArray *eventArray = [eventStore eventsMatchingPredicate:predicateEvent];
the eventArray contains only 8 elements...and where are the other 20? please i'm going crazy someone can help me?
On your device, go to: Settings > Mail, Contacts, Calendars, and under the Calendars sub-section go to Sync > All Events. Not just events from the past 30, 60 days, etc.

"Week of the year" Algorithm needs improvements

I have an algorithm which scans through data read from a .csv file(approx 3700 lines) and assess's which trading week of the year each entry is in by running a count++ for every Sunday of that year and assigning the count value as the trading week when the date falls within that week.
It's working but performance is lagging. It is the 3rd function running using Task.Factory.StartNew (I have also tried parallel.Invoke).
Results of timing tests.
before: 00:00:05.58
after: 00:00:23.27
UPDATE
Added break after each trading week is set. Time improved but still slow.
new time: 00:00:15.74
For our purposes the 1st week of the year is week 1(not 0) and is defined as from the first day of the year until the Sunday. If the first day of the year is a Sunday the length of week 1 is 1 day.
private void SetDefiniteWeeks()
{
string FileLoc = FilePath + Market + ".csv";
string[] Data = File.ReadAllLines(FileLoc);
var FileData = from D in Data
let DataSplit = D.Split(',')
select new
{
Date = DateTime.Parse(DataSplit[0]),
ClosingPrice = double.Parse(DataSplit[4])
};
//assign each date to it's relevant week
TradingWeek TW;
List<TradingWeek> tradingWeek = new List<TradingWeek>();
foreach (var pe in FileData)
{
// DateTime dt = pe.Date;
int Year = pe.Date.Year;
string End_of_Week = "Sunday";
int WeekCount = 0;
DateTime LoopDate_Begin = new DateTime(Year,1,1);
DateTime LoopDate_End = new DateTime(Year,12,31);
do
{
if (LoopDate_Begin.DayOfWeek.ToString() == End_of_Week)
{
WeekCount++;
if (LoopDate_Begin.DayOfYear > pe.Date.DayOfYear && LoopDate_Begin.DayOfYear < (pe.Date.DayOfYear + 7))
{
TW = new TradingWeek { Week = WeekCount, Date = pe.Date };
tradingWeek.Add(TW);
break;
}
}
LoopDate_Begin = LoopDate_Begin.AddDays(1);
} while (LoopDate_Begin.Date.ToString() != LoopDate_End.Date.ToString());
}
}
Please help.
UPDATE
NEW TIME
00:00:06.686
A vast improvement. Thanks all for your help.
Revised code:
CalendarWeekRule cw = CalendarWeekRule.FirstDay;
var calendar = CultureInfo.CurrentCulture.Calendar;
var trad_Week = (from pe in FileData
select new TradingWeek
{
Date = pe.Date,
Week = (calendar.GetWeekOfYear(pe.Date, cw,DayOfWeek.Sunday))
}).ToList();
Im not sure if this is what you want but after reading the comments I got the feeling that this might work (?)
var calendar = CultureInfo.CurrentCulture.Calendar;
var tradingWeek = (from pe in FileData
select new TradingWeek
{
Date = pe.Date,
Week = calendar.GetWeekOfYear(pe.Date, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
}).ToList();
Edit: Changed to CalendarWeekRule.FirstDay since it's (more?) what OP is looking for.
Three quick thoughts:
Why are you only adding one day each time and checking to see if it's Sunday. Surely once you have found your first Sunday you can add seven days to find the next one?
If you order your pes by DateTime before you start then you don't need to restart at the beginning of the year for each one, you can pick up where you left off.
As Nicolas says, break after adding the trading week. No need to go through the rest of the year after you already know what the answer is.
I guess you'll end up with something like this (may or may not actually work, but should be close enough)
TradingWeek TW;
List<TradingWeek> tradingWeek = new List<TradingWeek>();
string End_of_Week = "Sunday";
var orderedData = FileData.OrderBy(x => x.Date)
DateTime LoopDate_Begin = new DateTime(orderedData[0].Date.Year,1,1);
int WeekCount = 1;
while (LoopDate_Begin.DayOfWeek.ToString() != End_of_Week)
{
LoopDate_Begin = LoopDate_Begin.AddDays(1);
}
foreach (var pe in orderedData)
{
do
{
if (LoopDate_Begin.DayOfYear > pe.Date.DayOfYear && LoopDate_Begin.DayOfYear < (pe.Date.DayOfYear + 7))
{
TW = new TradingWeek { Week = WeekCount, Date = pe.Date };
tradingWeek.Add(TW);
break;
}
WeekCount++;
LoopDate_Begin = LoopDate_Begin.AddDays(7);
} while (true); //need to be careful here
}
if I get you correctly, you don't need to look any further as soon as you've added your TradingWeek
So, you can
break;
after
tradingWeek.Add(TW);
You could then even leave out the
&& LoopDate_Begin.DayOfYear < (pe.Date.DayOfYear + 7)
condition since the first part is going to be true only once: for your desired interval.
You might even go for a loopless approach by dividing the number of days since your starting week by 7 - and doing some cleaning up work ;)
Can you get rid of your do loop altogether by calculating the Week Number directly? Something like the accepted answer here.
Following #nicolas78's response, something like this should work
int Year = pe.Date.Year;
DateTime Year_Begin = new DateTime(Year,1,1);
int Jan1DayOfWeek = Year_Begin.DayOfWeek;
foreach (var pe in FileData)
{
int WeekCount = (pe.Date.DayOfYear - Jan1DayOfWeek) % 7 + 1;
TradingWeek TW = new TradingWeek { Week = WeekCount, Date = pe.Date };
tradingWeek.Add(TW);
}
Depending on how DayOfWeek and DayOfYear count, that is from 0 or 1, and how your mod operation work, you may need to tweak the WeekCount computation a bit.
There's a built-in feature to get the week of the year based on the date in .NET. An example is shown below, but it may need some tweaking to fit your business scenario:
System.Globalization.CultureInfo myCI = new System.Globalization.CultureInfo("en-US");
int week = myCI.Calendar.GetWeekOfYear(DateTime.Now.ToUniversalTime(), System.Globalization.CalendarWeekRule.FirstFourDayWeek, System.DayOfWeek.Sunday);
You don't need to count at all - just do a quick calculation. This assumes that a partial week at the start of the year is week 1 and week 2 begins on the first Monday.
List<TradingWeek> tradingWeek = new List<TradingWeek>();
foreach (var pe in FileData)
{
var date = pe.Date;
while (date.DayOfWeek != DayOfWeek.Sunday)
date = date.AddDays(1);
var week = date.DayOfYear/7+1;
var TW = new TradingWeek {Week = week, Date = pe.Date};
tradingWeek.Add(TW);
}

Resources