I have an array of dictionaries which results from an Core Data fetch request with results type of NSDictionary:
request.resultType = NSDictionaryResultType;
request.returnsDistinctResults = YES;
request.propertiesToFetch = #[#"endCalYear",#"endMonth",#"periodLength"];
A sample result NSArray of NSDictionary looks as follows:
{
endCalYear = 2007;
endMonth = 12;
periodLength = 12;
},
{
endCalYear = 2006;
endMonth = 9;
periodLength = 3;
},
{
endCalYear = 2006;
endMonth = 6;
periodLength = 3;
},
{
endCalYear = 2006;
endMonth = 3;
periodLength = 3;
}
What would be the most efficient way to create (three) separate arrays endCalYear = 2006, 2007, 2008; endMonth = 3, 9, 12 and periodLength = 3, 6, 12 from the NSArray given?
Thank you!
You can use valueForKey:
NSArray *endCalYearArray = [resultArray valueForKey:#"endCalYear"];
Related
I have an array of dictionaries in following format.
myarary = {day = 0; hour = 1; value = 0;},{day = 0; hour = 2; value = 0;}.... {day 6 =1; hour =23; value =1;}
So basically 7 days, 24 hours for each day and values 1 or 0 for each hour.
hence total of 168 dictionaries in my array.
Now my task is to extract values for a range of hours for a given day. For example, for day 6 I would have to extract hours slot between 2, 9 and another slot between 15 and 18 and so on.
I manage to solve the problem, with a nest for loop in following format
for (i =< start_of_hour_slot;i=<last_hour_of_slot); i++)
for(j = 0; j<=6; j++)
Now this works, but its too lengthy and my code is filled with loops, there must be easier way with fast enumeration?
Secondly my for loops doesn't give me flexibility.
I like to be in a position, where I can simply extract lets say for day 7, three different hours slots, along side the values.
or maybe for multiple days like, day 3,4,5 slots 2-9, 11,15...
You can change your array size and format, since your data is clear, just need to make the array size to 168, and put the value 0 or 1 directly into the array. The first 24 elements put the array the day0 values, and the next 24 elements put the day1 values, ..., the last 24 elements put the day6 values. If you want to extract the values of day 3,4,5 slots 2-9, 11,15, just fetch the elements index of 3*6+2 ~ 3*6+9, 4*6+11, 5*6+15 in the array.
As #vadian suggested NSCompoundPredicate should work for what you're attempting to accomplish. It looks like you may have a few typos in the NSPredicate you posted in your comments which is why it's failing to parse.
#import "ViewController.h"
#interface ViewController ()
#property (strong, nullable) NSArray <NSDictionary *> *generatedArray;
- (NSArray <NSDictionary *> *)_generateFakeDictionaryArray;
- (NSPredicate *)_predicateForDays:(NSArray <NSNumber *> *)days andHours:(NSArray <NSNumber *> *)hours;
- (NSPredicate *)_predicateForDays:(NSArray <NSNumber *> *)days andHoursBetween:(NSArray <NSNumber *> *)hoursBetween;
- (NSPredicate *)_predicateForDaysBetween:(NSArray <NSNumber *> *)daysBetween andHours:(NSArray <NSNumber *> *)hours;
- (NSPredicate *)_predicateForDaysBetween:(NSArray <NSNumber *> *)daysBetween andHoursBetween:(NSArray <NSNumber *> *)hoursBetween;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.generatedArray = [self _generateFakeDictionaryArray];
}
- (void)viewDidAppear:(BOOL)animated {
// one day multiple hour slots
NSPredicate *specificDaysSpecificHours = [self _predicateForDays:#[#(6)] andHours:#[#(7), #(8), #(22)]];
// multiple days hoursBetween
NSPredicate *daysBetweenHoursBetween = [self _predicateForDaysBetween:#[#(3), #(5)] andHoursBetween:#[#(2), #(9)]];
// days between, specific hours
NSPredicate *daysBetweenSpecificHours = [self _predicateForDaysBetween:#[#(3), #(5)] andHours:#[#(11), #(15)]];
NSCompoundPredicate *compPred = [NSCompoundPredicate orPredicateWithSubpredicates:#[specificDaysSpecificHours, daysBetweenHoursBetween, daysBetweenSpecificHours]];
NSArray <NSDictionary *> *filteredArray = [self.generatedArray filteredArrayUsingPredicate:compPred];
NSLog(#"Filtered array = %#", filteredArray);
}
- (NSArray <NSDictionary *> *)_generateFakeDictionaryArray {
NSInteger daysInWeek = 7;
NSInteger hoursInDay = 24;
NSMutableArray *dictArray = [NSMutableArray arrayWithCapacity:hoursInDay * daysInWeek];
for (NSInteger day = 0; day < daysInWeek; day++) {
for (NSInteger hour = 0; hour < hoursInDay; hour++) {
NSDictionary *dayHourDict = #{#"day" : #(day), #"hour" : #(hour), #"value" : #(arc4random() % 2)};
[dictArray addObject:dayHourDict];
}
}
return [NSArray arrayWithArray:dictArray];
}
- (NSPredicate *)_predicateForDays:(NSArray <NSNumber *> *)days andHours:(NSArray <NSNumber *> *)hours {
return [NSPredicate predicateWithFormat:#"day IN %# AND hour IN %#", days, hours];
}
- (NSPredicate *)_predicateForDays:(NSArray <NSNumber *> *)days andHoursBetween:(NSArray <NSNumber *> *)hoursBetween {
return [NSPredicate predicateWithFormat:#"day IN %# AND hour BETWEEN %#", days, hoursBetween];
}
- (NSPredicate *)_predicateForDaysBetween:(NSArray <NSNumber *> *)daysBetween andHours:(NSArray <NSNumber *> *)hours {
return [NSPredicate predicateWithFormat:#"day BETWEEN %# AND hour IN %#", daysBetween, hours];
}
- (NSPredicate *)_predicateForDaysBetween:(NSArray <NSNumber *> *)daysBetween andHoursBetween:(NSArray <NSNumber *> *)hoursBetween {
return [NSPredicate predicateWithFormat:#"day BETWEEN %# AND hour BETWEEN %#", daysBetween, hoursBetween];
}
#end
Which generates this as an output:
Filtered array = (
{
day = 3;
hour = 2;
value = 1;
},
{
day = 3;
hour = 3;
value = 0;
},
{
day = 3;
hour = 4;
value = 0;
},
{
day = 3;
hour = 5;
value = 1;
},
{
day = 3;
hour = 6;
value = 0;
},
{
day = 3;
hour = 7;
value = 0;
},
{
day = 3;
hour = 8;
value = 0;
},
{
day = 3;
hour = 9;
value = 1;
},
{
day = 3;
hour = 11;
value = 0;
},
{
day = 3;
hour = 15;
value = 1;
},
{
day = 4;
hour = 2;
value = 1;
},
{
day = 4;
hour = 3;
value = 1;
},
{
day = 4;
hour = 4;
value = 1;
},
{
day = 4;
hour = 5;
value = 1;
},
{
day = 4;
hour = 6;
value = 1;
},
{
day = 4;
hour = 7;
value = 1;
},
{
day = 4;
hour = 8;
value = 0;
},
{
day = 4;
hour = 9;
value = 1;
},
{
day = 4;
hour = 11;
value = 1;
},
{
day = 4;
hour = 15;
value = 1;
},
{
day = 5;
hour = 2;
value = 1;
},
{
day = 5;
hour = 3;
value = 0;
},
{
day = 5;
hour = 4;
value = 1;
},
{
day = 5;
hour = 5;
value = 0;
},
{
day = 5;
hour = 6;
value = 0;
},
{
day = 5;
hour = 7;
value = 1;
},
{
day = 5;
hour = 8;
value = 1;
},
{
day = 5;
hour = 9;
value = 0;
},
{
day = 5;
hour = 11;
value = 0;
},
{
day = 5;
hour = 15;
value = 1;
},
{
day = 6;
hour = 7;
value = 1;
},
{
day = 6;
hour = 8;
value = 1;
},
{
day = 6;
hour = 22;
value = 1;
}
)
https://developer.apple.com/documentation/foundation/nspredicate?language=objc
https://developer.apple.com/documentation/foundation/nscompoundpredicate?language=objc
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html#//apple_ref/doc/uid/TP40001789
I have an array of dictionaries of options with categories. I want the options to be under the category. As of now, my categories are repeating as to how many times my options are added.
Given this:
(
{
multiOptnCatId = 4;
multiOptnItem = 1344;
},
{
multiOptnCatId = 7;
multiOptnItem = 2253;
},
{
multiOptnCatId = 4;
multiOptnItem = 1343;
},
{
multiOptnCatId = 4;
multiOptnItem = 1346;
},
{
multiOptnCatId = 4;
multiOptnItem = 1342;
},
{
multiOptnCatId = 4;
multiOptnItem = 1345;
}
)
What's the efficient way I can convert it to:
(
{
multiOptnCatId = 4;
multiOptnItem = (1342, 1343, 1344, 1345, 1346);
},
{
multiOptnCatId = 7;
multiOptnItem = (2253);
}
)
Thank you guys! :)
NSArray *array = ...; // your input array
// All categories as array:
NSArray *catArray = [array valueForKey:#"multiOptnCatId"];
// All categories as set (to remove duplicates):
NSSet *catSet = [NSSet setWithArray:catArray];
NSMutableArray *rearranged = [NSMutableArray array];
// For all categories ...
for (NSString *cat in catSet) {
// Get matching dictionaries for this category:
NSArray *filtered = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"multiOptnCatId = %#", cat]];
// Get "multiOptnItem" values for this category:
NSArray *items = [filtered valueForKey:#"multiOptnItem"];
// Add category + multiOptnItem values to rearranged array:
[rearranged addObject:#{#"multiOptnCatId":cat, #"multiOptnItem":items}];
}
I have an array(seachResult) which contains dictionaries and I want to sort this array according to 'price' key in the dictionary that is a number in string format.
I tried this code but it doesn't work for sorting 'price' but it works for pid which is a number.
how can I sort it according 'price' (number in string format)?
NSSortDescriptor *sortByPrice = [NSSortDescriptor sortDescriptorWithKey:#"price" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortByPrice];
NSArray *sortedArray = [self.seachResult sortedArrayUsingDescriptors:sortDescriptors];
NSLog(#"%#",sortedArray );
here is sample data for self.searchResult:
2013-07-17 02:04:55.012 MyApp[57014:16a03] sorted array of dictionaries: (
{
cid = 2;
image = "http:///images/loginlogo.png";
latitude = "48.245565";
longitude = "16.342333";
manual = "";
movie = "http://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v";
pcode = 023942435228;
pid = 1;
pname = "example product";
price = "12.00";
qrcode = "";
rid = 1;
rname = "Example Retailer Name";
sale = 0;
"sale_percent" = 0;
"sale_price" = "0.00";
text = "here is text about sample product number 1...\nasdasdasda\nsdfsdfsd\nSdfsdf\nSDfsdfs\ndfsdfsdf\n\n\n";
},
{
cid = 2;
image = "http:///testImage.png";
latitude = "48.245565";
longitude = "16.342333";
manual = "";
movie = "";
pcode = 1;
pid = 2;
pname = "sample product 2";
price = "126.00";
qrcode = "";
rid = 1;
rname = "Example Retailer Name";
sale = 1;
"sale_percent" = 20;
"sale_price" = "99.99";
text = "here is text about sample product number 2...\nblah blah blah\nasdasdasd\nASdasdas\nASdasdasd";
},
{
cid = 1;
image = "";
latitude = "";
longitude = "";
manual = "";
movie = "";
pcode = 1;
pid = 3;
pname = "test product";
price = "46.00";
qrcode = "";
rid = 2;
rname = "";
sale = 0;
"sale_percent" = 0;
"sale_price" = "35.00";
text = "some text here...
\nasdasd
\nasd
\na
\nsd
\nas
\nd";
}
)
I also tried this code :
NSSortDescriptor *hopProfileDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"price"
ascending:YES];
NSArray *descriptors = [NSArray arrayWithObjects:hopProfileDescriptor, nil];
NSArray *sortedArrayOfDictionaries = [self.seachResult
sortedArrayUsingDescriptors:descriptors];
NSLog(#"sorted array of dictionaries: %#", sortedArrayOfDictionaries);
but still doesn't work.
I think the issue is that in your self.searchResult array the price data is differently formatted for the objects in the array.
The first object in the array it's formatted like price = 12; (probably a NSDecimalNumber)
The second object in the array it's formatted like price = "125.99"; (proably a NSString)
NSArray *testSorted = [test sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2) {
NSString *price1 = obj1[#"price"];
NSString *price2 = obj2[#"price"];
NSNumber *n1 = [NSNumber numberWithFloat:[price1 floatValue]];
NSNumber *n2 = [NSNumber numberWithFloat:[price2 floatValue]];
return [n1 compare:n2];
}];
Since your price data seems to vary (NSString vs NSNumber) you might try instead using sortedArrayUsingComparator:. eg:
NSArray *sortedArray = [unsortedArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
id value1 = [obj1 objectForKey:#"price"];
float float1 = [value1 floatValue];
id value2 = [obj2 objectForKey:#"price"];
float float2 = [value2 floatValue];
if (float1 < float2) {
return NSOrderedAscending;
}
else if (float1 > float2) {
return NSOrderedDescending;
}
return NSOrderedSame;
}];
This is kinda ugly but should get you started. It's also fragile--if you get something other than NSNumber or NSString for the price it'll likely crash.
Is there an easy way to transform an array of numbers to an arrays with the numbers in sequence?
NSArray *numbers = #[#1,#2,#5,#3];
// Transformed arrays
//NSArray *numbersInSequence = #[#1,#2,#3];
//NSArray *numbersInSequence2 = #[#5];
EDIT:
I modified the code in Richard's answer to get it to work.
NSArray *arraysBySplittingNumbersInOrder(NSArray *input) {
// sort 'input'
input = [input sortedArrayUsingSelector:#selector(compare:)];
NSMutableArray *results = [NSMutableArray array];
if (input.count) {
int start = 0;
int last = INT_MIN;
for (int i = 0; i < input.count; i++) {
BOOL lastItem = i == input.count - 1;
// The first item of the array
if (i == 0) {
if (lastItem) {
[results addObject:input];
break;
}
last = [input[i] intValue];
continue;
}
int cur = [input[i] intValue];
if (cur != last + 1) {
// pull out the next array
[results addObject:[input subarrayWithRange:NSMakeRange(start, i - start)]];
start = i;
}
// The last item of the array
if (lastItem) {
[results addObject:[input subarrayWithRange:NSMakeRange(start, i - start + 1)]];
}
last = cur;
}
}
return results;
}
Here's a rather simple solution:
NSArray *arraysBySplittingNumbersInOrder(NSArray *input)
{
// sort 'input'
input = [input sortedArrayUsingSelector:#selector(compare:)];
NSMutableArray *results = [NSMutableArray array];
if (input.count)
{
int start = 0;
int last = INT_MIN;
for (int i = 0; i <= input.count; i++)
{
if (i == 0)
{
last = [input[i] intValue];
continue;
}
if (i == input.count)
{
if (i != start + 1)
{
[results addObject:[input subarrayWithRange:NSMakeRange(start, i - start)]];
continue;
}
}
int cur = [input[i] intValue];
if (cur != last + 1)
{
// pull out the next array
[results addObject:[input subarrayWithRange:NSMakeRange(start, i - start)]];
start = i;
}
last = cur;
}
}
return results;
}
int main()
{
NSArray *input = #[ #1, #3, #4, #7, #8, #12, #13, #14 ];
NSLog(#"%#", input);
NSLog(#"%#", arraysBySplittingNumbersInOrder(input));
}
Output:
2012-11-27 07:55:04.609 TestProj[35890:303] (
1,
3,
4,
7,
8,
12,
13,
14
)
2012-11-27 07:55:04.611 TestProj[35890:303] (
(
1
),
(
3,
4
),
(
7,
8
),
(
12,
13,
14
)
)
I don't think there's an easy way to do this; you'll probably have to do at least part of the work yourself.
My suggestion would be to sort the array an then iterate through it, building the sections as you go. Whenever you hit a "jump", i.e. a non-consecutive number, this concludes your current section and starts a new one.
NSLog give me this when i print some NSDictionary object. I see, that in this NSDictionary are few NSDictionary objects. i must to send this to UITextView, but this must be one list without {ExifAux}, {Exif}, {IPTC}, {TIFF}. how can i do this?
2012-01-21 13:33:23.818 foto-edytor[7838:17903] {
ColorModel = RGB;
DPIHeight = 240;
DPIWidth = 240;
Depth = 8;
PixelHeight = 900;
PixelWidth = 598;
"{ExifAux}" = {
ImageNumber = 5280;
LensID = 159;
LensInfo = (
35,
35,
"1.8",
"1.8"
);
LensModel = "35.0 mm f/1.8";
SerialNumber = 6055523;
};
"{Exif}" = {
ApertureValue = "3.356144";
BodySerialNumber = 6055523;
ColorSpace = 1;
ComponentsConfiguration = (
1,
2,
3,
0
);
Contrast = 0;
CustomRendered = 0;
DateTimeDigitized = "2011:11:12 11:54:18";
DateTimeOriginal = "2011:11:12 11:54:18";
DigitalZoomRatio = 1;
ExifVersion = (
2,
2,
1
);
ExposureBiasValue = "-1.333333";
ExposureMode = 0;
ExposureProgram = 3;
ExposureTime = "0.01666667";
FNumber = "3.2";
FileSource = 3;
Flash = 0;
FlashPixVersion = (
1,
0
);
FocalLenIn35mmFilm = 52;
FocalLength = 35;
GainControl = 1;
ISOSpeedRatings = (
400
);
LensModel = "35.0 mm f/1.8";
LensSpecification = (
35,
35,
"1.8",
"1.8"
);
LightSource = 0;
MaxApertureValue = "1.6";
MeteringMode = 2;
PixelXDimension = 1442971648;
PixelYDimension = "-2080178176";
Saturation = 0;
SceneCaptureType = 0;
SceneType = 1;
SensingMethod = 2;
Sharpness = 0;
ShutterSpeedValue = "5.906891";
SubjectDistRange = 0;
SubjectDistance = "1.41";
SubsecTimeDigitized = 25;
SubsecTimeOriginal = 25;
UserComment = SZULC;
WhiteBalance = 0;
};
"{IPTC}" = {
Byline = "SZULC TOMASZ";
CopyrightNotice = "SZULC TOMASZ";
};
"{TIFF}" = {
Artist = "SZULC TOMASZ";
Copyright = "SZULC TOMASZ";
DateTime = "2012:01:20 17:50:58";
Make = "NIKON CORPORATION";
Model = "NIKON D300S";
ResolutionUnit = 2;
Software = "Ver.1.01";
XResolution = 240;
YResolution = 240;
"_YCbCrPositioning" = 1;
};
}
It's not the most beautiful way, but I guess this should work:
- (NSString *)stringOutputForDictionary:(NSDictionary *)inputDict {
NSMutableString * outputString = [NSMutableString stringWithCapacity:256];
NSArray * allKeys = [inputDict allKeys];
for (NSString * key in allKeys) {
if ([[inputDict objectForKey:key] isKindOfClass:[NSDictionary class]]) {
[outputString appendString: [self stringOutputForDictionary: (NSDictionary *)inputDict]];
}
else {
[outputString appendString: key];
[outputString appendString: #": "];
[outputString appendString: [[inputDict objectForKey: key] description]];
}
[outputString appendString: #"\n"];
}
return [NSString stringWithString: outputString];
}