Tricky NSArray iteration - ios

I have an NSArray(mainArray) that contains 28 items and I want to divide that array into 7 arrays containing 4 items each. Is it possible for me to grab the first 4 items from mainArray, add them to a subArray, then grab the NEXT 4 items and add them to the subArray, and so on until I iterate through all 28 items? If it is possible, how?
Here's my mainArray:
{item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18, item19, item20, item21, item22, item23, item24, item25, item26, item27, item28}
I need to change it to this (groupedArray):
{item1, item2, item3, item4}, {item5, item6, item7, item8}, {item9, item10, item11, item12}, {item13, item14, item15, item16}, {item17, item18, item19, item20}, {item21, item22, item23, item24}, {item25, item26, item27, item28}
This is what I've tried:
int i; int j;
for (i=0, j=1; i<28; i++, j*=4 ) {
NSArray *smallArray = [mainArray subarrayWithRange:NSMakeRange(0, j)];
[groupedArray addObjectsFromArray:smallArray];
}
Thanks,
DB

Some of your indexes are off. You want something like this:
NSArray *mainArray = ... // the full array
NSMutableArray *groupedArray = ... // the new array
for (NSUInteger i = 0; i < mainArray.count; i += 4) {
NSArray *smallArray = [mainArray subarrayWithRange:NSMakeRange(i, 4)];
[groupedArray addObjectsFromArray:smallArray];
}
Please note that this code will crash if the number of elements in mainArray isn't a multiple of 4.

Related

How to sort one array based on the order of its object in another array in objective-c?

I have list which is sorted by user. then I get the list from server again.
some elements might be deleted or added.
I want to sort the new array based on the sorting of the previous array then add new elements.
Example
oldElementList: [1, 4, 2, 8] ---> user set this order
newElementList: [1, 4, 3, 8]
What I want as output is: [1, 4, 8, 3]
Actually element are not numbers they are objects. and when they are gotten from server some of their property values might have changed.
My answer:
for (ElementModel *oldElement in oldElementList) {
for (ElementModel * newElement in newElementList) {
if ([newElement.number isEqualToString: oldElement.number]) {
[sortedArray addObject: newElement];
[newElementList removeObject: newElement];
break;
}
}
}
for (ElementModel *newElement in newElementList) {
[sortedArray addObject: newElement];
}
I don't think my answer is ok, I want to make it better in performance or in any other aspect that I have not considered.
Which sorting algorithm is appropriate depends very much on your data, e.g.:
- Is the data set to be sorted large (only then, a sophisticated algorithms may pay off)?
- Is the data set to be sorted completely random or presorted?
From your description it seems to me that you have a large data set (otherwise any algorithms giving the correct result would be probably fine, including your own that has a O(n^2) complexity), and that it is presorted, i.e. there are only only a few additions and deletions (otherwise it may not be so important to keep the original sorting).
If so, what about the following algorithm (sorry, it is in Swift, but could surely easily be converted to Obj-C):
let old = [1, 4, 2, 7, 8]
let new = [1, 4, 3, 8, 2]
var oldIndexed: [Int: Int] = [:]
for i in 0 ..< old.count {
oldIndexed[old[i]] = i
}
var newIndexed: [Int: Int] = [:]
for i in 0 ..< new.count {
newIndexed[new[i]] = oldIndexed[new[i]] ?? old.count
}
var resultArray: [(Int, Int)] = []
for (key, value) in newIndexed {
resultArray.append((key, value))
}
resultArray = resultArray.sorted { (first, second) -> Bool in
first.1 < second.1
}
let result = resultArray.map{ $0.0 } // Here: [1, 4, 2, 8, 3]
The idea is to give the old data elements an index, and every new data element the same index. This is done by using dictionaries, since there every element can be accessed by its key in O(1). New elements get a larger index (this could also be a counter to make it clearer). Then the new dictionary is converted back to an array, that is then sorted by its index. Eventually, the index is dropped, and the result is ready.
I guess, the complexity of this algorithm is determined by the sort function that should be optimal since it is implemented in the standard library.
EDIT:
I did not program in Obj-C for a long time, but tried it just for fun once more:
NSArray *old = #[#1, #4, #2, #7, #8];
NSArray *new = #[#1, #4, #3, #8, #2];
NSMutableDictionary *oldIndexed = [[NSMutableDictionary alloc] init];
for (int i = 0; i < old.count; i++) {
[oldIndexed setValue:[NSNumber numberWithInt: i] forKey: old[i]];
}
NSMutableDictionary *newIndexed = [[NSMutableDictionary alloc] init];
long counter = old.count;
for (int i = 0; i < old.count; i++) {
NSNumber *oldIndexOfNewValue = oldIndexed[new[i]];
NSNumber *newIndex;
if (oldIndexOfNewValue != nil) {
newIndex = oldIndexOfNewValue;
} else {
newIndex = [NSNumber numberWithLong: counter];
counter++;
}
[newIndexed setValue: newIndex forKey: new[i]];
}
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSArray *allKeysInNewIndexed = newIndexed.allKeys;
for (int i = 0; i < allKeysInNewIndexed.count; i++) {
NSNumber *nextKey = allKeysInNewIndexed[i];
NSArray *nextPair = #[nextKey, newIndexed[nextKey]];
[resultArray addObject: nextPair];
}
NSArray *sortedResultArray;
sortedResultArray = [resultArray sortedArrayUsingComparator: ^NSComparisonResult(NSArray *first, NSArray *second) {
NSNumber *firstIndex = first[1];
NSNumber *secondIndex = second[1];
return [firstIndex compare: secondIndex];
}];
NSMutableArray * result = [[NSMutableArray alloc] init];
for (int i = 0; i < sortedResultArray.count; i++) {
[result addObject: sortedResultArray[i][0]];
}

Array of dictionary value changes is reflect in all the values

I have NSMutableArray and Added NSMutableDictionary
If i update one value for specific row then all the values changes in NSMutableDictionary.
NSIndexPath *qtyIndex
-(void)demoDefaultCartValues{
[dict_CartItems setValue:#"Item 1 KK Demo" forKey:#"DIC_PRODUCT_NAME"];
[dict_CartItems setValue:#" KK Demo" forKey:#"SELLER_NAME"];
[dict_CartItems setValue:#"1" forKey:#"QTY_VALUE"];
[dict_CartItems setValue:#"42" forKey:#"SIZE_VALUE"];
[dict_CartItems setValue:#"1250" forKey:#"PRICE_VALUE"];
[dict_CartItems setValue:#"1500" forKey:#"DISCOUNT_VALUE"];
for (int i = 0; i <= 5; i++) {
[cartListArray addObject:dict_CartItems];
}
}
#pragma mark - DropDown Delegate
-(void)dropDownView:(UIView *)ddView AtIndex:(NSInteger)selectedIndex{
[[cartListArray objectAtIndex:qtyIndexPath.row] setValue:[sizeArrayList objectAtIndex:selectedIndex] forKey:#"QTY_VALUE"];
NSLog(#"What %#",cartListArray);
}
If I update qty 1 to 5 then all dictionary values QTY_Value changes to 5.
Use new Objective-C features (more than 5 years old) to make this more readable. And add six different mutable dictionaries to the array:
NSDictionary* dict = { #"DIC_PRODUCT_NAME":#"Item 1 KK Demo",
#"SELLER_NAME":#" KK Demo",
#"QTY_VALUE": #"1",
etc.
};
for (NSInteger i = 0; i < 6; ++i)
[cartListArray addObject: [dict mutableCopy]];
and later:
-(void)dropDownView:(UIView *)ddView atIndex:(NSInteger)selectedIndex{
cartListArray [qtyIndexPath.row] [#"QTY_VALUE] = sizeArrayList [selectedIndex];
}
cartListArray should be declared as
NSMutableArray <NSMutableDictionary*> *cartListArray;
Now what I would really recommend that you don't store a dictionary at all, but declare a model class. So you don't have to use strings for quantity etc. but NSInteger. Also that cartListArray isn't mutable if you don't want to modify it after it has been initialised. Keep things immutable whenever you can.
This is obvious
when you are adding NSMutableDictionary to array, array have the reference of that dictionary inside.
Now what you are doing is inserting same dictionary multiple times in array. so when you change a single object in array. all the places are get effected. keeping same object of Dictionary always causes this issue.
Solution for this problem is create a new object every time before you insert into array.
Hope it is helpfult to you
The problem is that your code uses the same dictionary and it's a refrence value , so it's a shallow copy of the same one , you may create a new one every iteration
-(void)demoDefaultCartValues{
for (int i = 0; i <= 5; i++) {
NSMutableDictionary*dict_CartItems = [ NSMutableDictionary new];
[dict_CartItems setValue:#"Item 1 KK Demo" forKey:#"DIC_PRODUCT_NAME"];
[dict_CartItems setValue:#" KK Demo" forKey:#"SELLER_NAME"];
[dict_CartItems setValue:#"1" forKey:#"QTY_VALUE"];
[dict_CartItems setValue:#"42" forKey:#"SIZE_VALUE"];
[dict_CartItems setValue:#"1250" forKey:#"PRICE_VALUE"];
[dict_CartItems setValue:#"1500" forKey:#"DISCOUNT_VALUE"];
[cartListArray addObject:dict_CartItems];
}
}
Or you can use copy / mutableCopy
for (int i = 0; i <= 5; i++) {
[cartListArray addObject:[dict_CartItems mutableCopy]];
}

NSMutableArray has 6 (some example) items. 3 IDs and 3 arrays (info about those 3 IDs). How to remove those numbers (IDs)

(
65,
61,
82,
{
FOMobilePhone = "";
FOName = "XXX";
FOTitle = "PRODUCTION DIRECTOR";
FOWorkEMail = "AAA#example.com";
FOWorkPhone = "+12345";
Id = 65;
},
{
FOMobilePhone = "";
FOName = "BBB";
FOTitle = "GSC EGYPT OPERATION LEAD";
FOWorkEMail = "BBB#example.com";
FOWorkPhone = "+12345";
Id = 61;
},
{
FOMobilePhone = "";
FOName = "CCC";
FOTitle = "PRODUCTION, DIRECTOR";
FOWorkEMail = "CCC#example.com";
FOWorkPhone = "+12345";
Id = 82;
}
}
First 3 items are IDs and remaining 3 arrays are their respective data. NSMutableArray has 6 (some example) items. 3 IDs and 3 arrays (info about those 3 IDs). How to remove those numbers (IDs)?
Let someArray = NSMUtableArray you are getting from server.
NSMutableIndexSet *discardedItems = [NSMutableIndexSet indexSet];
NSUInteger index = 0;
for (id someObject in someArray) {
if ([someObject isKindOfClass:[NSString class]]){
[discardedItems addIndex:index];
}
index++;
}
[someArray removeObjectsAtIndexes:discardedItems];
Finally , someArray will have only the data without IDs.
try this:
if NSMutableArray name is arr1 then you can do like this to remove three ID:
[arr1 removeObject:0];
[arr1 removeObject:1];
[arr1 removeObject:2];
You don't say what language you're using. If it's Swift, you could write a filter command that would get rid of the Int items.
If it's Objective-C you don't have that option, but you could do it various other ways. I'd suggest using filterUsingPredicate (if it's a mutable array) or filteredArrayUsingPredicate if it's an immutable array.

storing multiples values for particular key in an array of dictionaries not working iOS

i want to have an array which stores dictionaries with some key-value pair like shown below.
add = (
{
ans = abc;
que = Fdgdf;
},
{
ans = hi;
que = hello;
},
{
ans = GM;
que = dosa;
}
)
Here is what i tried.
for (int i=0; i<=[addKeyArray count]; i++) {
[_addDictNewQA setObject:[addKeyarray objectAtIndex:i] forKey:#"que"];
[_addDictNewQA setObject:[addValuesArray objectAtIndex:i] forKey:#"ans"];
[_addArrayNewQA addObject:_addDictNewQA];
}
here addKeyArray is the array which holds all the 'que' elements and addValuesArrray holds all the 'and' elements. but when i set these arrays to dictionary objects and add that dictionary to new array(_addArrayNewQA), it only display the last element like this-
add = (
{
ans = GM;
que = dosa;
},
{
ans = GM;
que = dosa;
},
{
ans = GM;
que = dosa;
}
)
Can anyone please tell me whats wrong in my code. Any help is appreciated.
That is because you are setting values in same object of NSMutableDictionary, also you dont need to have the NSMutableDictionary as global as you are using it in the for loop only.
You need to create new dictionary
for (int i=0; i<=[addKeyArray count]; i++) {
NSMutableDictionary *_addDictNewQA = [NSMutableDictionary new];
[_addDictNewQA setObject:[addKeyarray objectAtIndex:i] forKey:#"que"];
[_addDictNewQA setObject:[addValuesArray objectAtIndex:i] forKey:#"ans"];
}
[_addArrayNewQA addObject:_addDictNewQA];
You need to create a new inner dictionary each iteration. What you are doing is adding the same dictionary over and over and changing its contents so you end up with an array of dictionaries containing the last entry.
for (int i=0; i<=[addKeyArray count]; i++) {
NSDictionary *innerDict = #{
#"que" : addKeyArray[i],
#"ans" : addValuesArray[i]
};
[_addArrayNewQA addObject:innerDict];
}
And remove the _addDictNewQA instance variable.
Create dictionary in for loop. you need to create new dictionary every time. So, create mutable dictionary in for loop and add that dictionary to mutable array (your result array) which must not create (alloc and init) in for loop.
Your code seems that you have created your dictionary outside the for loop.!!

Comparing Dictionaries with Objects Value of Array in IOS

I am having N number of Dictionaries & having array that contains objects.
I need to iterate and check whether value for key EmployeeID of dictionary exists at Object. say obj.empId or not in array.
Dictionary looks like below
{
"Message":[
{
"EmpID": 3749,
"Dept": 10,
"EmployeeName": "John",
},
{
},
{
}]
} //so many dictionaries..not one
Example: I already have an array with 10 records say obj.empID holds from 1-10. From service I am getting 10 records say 10 dictionaries. In that key EmpID holds values 5-15.
So, How can I iterate the loop so that to identify that new records are retrieved with different EmpID's then existing Records.
Here is the Code I have done so far..
NSArray *responseArray=responseDict[#"Message"];
for (NSDictionary *dict in responseDict[#"Message"]) {
for (id key in responseDict) {
if ([key isEqualToString:#"EmpID"]) {
for (Employees *empObj in emparray)
{
BOOL isExists=YES;;
if (![empObj.empid isEqualToString:[responseDict objectForKey:key]]) {
isExists=NO;
break;
//here I need to do the logic..
}
}
}
}
}
But it will not get accurate results or logic is nor correct..
Please suggest any better solutions for above task or where I am going wrong..
Any Ideas or suggestions are appreciated..
Thanks..,
Without using so many loops, you may follow below code to check record is exist ot not.
NSArray *responseArray=responseDict[#"Message"];
for (Employees *empObj in emparray)
{
BOOL isExists=NO;
if ([[responseArray valueForKey:#"EmpID"]containsObject:empObj.empid]) {
isExists=YES;
NSLog(#"%# EmpID Exist",empObj.empid);
//here I need to do the logic..
}else{
NSLog(#"%# EmpID Not Exist",empObj.empid);
}
}
Dont use iterations, Code smartly, Use following code...
NSArray *responseArray=responseDict[#"Message"];
NSArray * empIdResponseArray = [responseArray valueForKeyPath:#"#unionOfObjects.EmpID"];
NSArray * empIdLocalArray = [emparray valueForKeyPath:#"#unionOfObjects.empid"];
NSMutableSet *empIdResponseSet = [NSMutableSet setWithArray: empIdResponseArray];
NSSet *empIdLocalSet = [NSSet setWithArray: empIdLocalArray];
[empIdResponseSet intersectSet: empIdLocalSet];
NSArray *commonElementArray = [empIdResponseSet allObjects];
NSMutableArray *newElementArray = [NSMutableArray arrayWithArray:empIdResponseArray];
[newElementArray removeObjectsInArray:commonElementArray];
for (int index = 0; index < newElementArray.count; index++)
{
NSMutableDictionary * dictEmp = [NSMutableDictionary dictionaryWithDictionary:[newElementArray objectAtIndex:index]];
NSLog(#"EMPLOYEE = %#",dictEmp);
// Add your Logic for new records only....
// Enjoy :)
}

Resources