Find numbers in array that appear 2 or more times - ios

I need to find duplicated numbers (that appear 2 or more times) in array how can I do it without using NSCountedSet?
This is a solution I did:
NSCountedSet *countedSet = [NSCountedSet setWithArray:array];
__block NSUInteger totalNumberOfDuplicates = 0;
[countedSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop)
{
NSUInteger duplicateCountForObject = [countedSet countForObject:obj];
if (duplicateCountForObject > 1)
totalNumberOfDuplicates += duplicateCountForObject;
NSLog(#"%# appears %ld times", obj, duplicateCountForObject);
}];

This is a solution that can be achieved using Swift, but you can use any language to achieve this result:
func checkDuplicatedNumbers()
{
let array = [1, 2, 3, 4, 0, 1, 5, 2, 1, 1, 1, 4]
var dictioanry = [Int: Int]()
for element in array
{
if let value = dictioanry[element] {
let newValue = value + 1
dictioanry[element] = newValue
} else {
dictioanry[element] = 1
}
}
for key in dictioanry.keys {
let count = dictioanry[key]
if (count > 1) {
print("Number \(key) repeats \(count) times")
}
}
}

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 to nested Dictionary in iOS?

There are a lot of questions with similar title but no one answers my question.
In my case I have an array:
["1", "2", "3", "4"]
And resulting dictionary should be:
["1": ["2": ["3": "4"]]]
How to convert it correctly? As I understand map, reduce and the similar functions doesn't have such functionality. And is it possible to do without of writing a recursive method?
Both Objective-C and Swift are applicable
A Swift solution, using reduce:
let a = ["1", "2", "3", "4"]
let d = a.dropLast(2).reversed()
.reduce([a[a.count - 2] : a[a.count - 1]]) { [$1 : $0] }
print(d) // ["1": ["2": ["3": "4"]]]
Here it is assumed that the array has at least 2 elements.
In our example, ["3", "4"] is the initial value for reduce,
and for the remaining elements in reverse order, a nested dictionary
is created in the closure with [$1 : $0].
The type of the result is [String: Any], which bridges to
NSDictionary if necessary.
//Your array
NSArray *a = #[#1,#2,#3,#4];
//Get the two last values (considering your array length must be at least 2 !
NSDictionary *last = #{a[a.count-2]:a[a.count-1]};
//In reverse order we assign last created dictionary to the current key, the array length must be superior than 3
for (NSInteger i = a.count - 3; i >= 0; i--)
last = #{a[i]:last};
NSLog(#"My dictionary %#", last);
Recursive option.
func toNestedDictionary(arr: [String]) -> [String: Any?]? {
if arr.isEmpty {
return nil
}
else if arr.count == 1 {
return Dictionary(dictionaryLiteral: (arr.first!, nil))
}
else if arr.count == 2 {
return Dictionary(dictionaryLiteral: (arr.first!, arr.last!))
}
else {
let head = arr.first!
let tail = arr.dropFirst()
return Dictionary(dictionaryLiteral: (head, toNestedDictionary(arr: Array(tail))))
}
}
print (toNestedDictionary(arr: ["1"]))
// Optional(["1": nil])
print (toNestedDictionary(arr: ["1", "2"]))
// Optional(["1": Optional("2")])
print (toNestedDictionary(arr: ["1", "2", "3"]))
// Optional(["1": Optional(["2": Optional("3")])])
print (toNestedDictionary(arr: ["1", "2", "3", "4"]))
// Optional(["1": Optional(["2": Optional(["3": Optional("4")])])])
Try below lines without recursion
NSArray *arr = #[#"1", #"2", #"3", #"4"];
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
for (int i = arr.count-2; i>=0;i--) {
if (i == arr.count-2) {
[dic setObject:arr[i+1] forKey:arr[i]];
} else {
NSDictionary *tempDic = dic;
dic = #{arr[i]:tempDic};
}
}
NSLog(#"Solution%#",dic);
This problem can be solved using recursive programming easily. Here is the solution using Swift;
var ary = ["1", "2", "3", "4"]
func recursive(array:[String]) -> Any {
if ary.count > 1 {
let key = ary.removeFirst()
return [key : recursive(array: array)]
} else {
return array.last!
}
}
let reuslt = recursive(array: ary)
And result is: ["1": ["2": ["3": "4"]]]
Given a list
var list = ["1", "2", "3", "4"]
you can write
if let lastValue = list.popLast(), let lastKey = list.popLast() {
let dict = list.reversed().reduce([lastKey:lastValue]) { [$1:$0] }
print(dict)
}
Result
["1": ["2": ["3": "4"]]]
Please note that this code only works if the list contains at least 2 elements
Found a simplier solution:
NSMutableArray *tempArr = [array mutableCopy];
while (tempArray.count > 1) {
id value = tempArr.lastObject;
[tempArr removeLastObject];
NSString *key = tempArr.lastObject;
[tempArr removeLastObject];
[tempArr addObject:#{key: value}];
}
id result = tempArr.firstObject;

It is possible to use array reduce concept from swift in objective c?

I have this lines of code in Swift:
let graphPoints:[Int] = [4, 2, 6, 4, 5, 8, 3]
let average = graphPoints.reduce(0, combine: +) / graphPoints.count
It is possible to "translate" this lines of code in objective c code?
It's not very clear for me how reduce combine concept works. I read about it but still is unclear.
I took the code from this tutorial: http://www.raywenderlich.com/90693/modern-core-graphics-with-swift-part-2
Please help. Thanks.
let's say you have some NSNumbers stored in an NSArray you can use this KVC collection operator:
NSArray *someNumbers = #[#0, #1.1, #2, #3.4, #5, #6.7];
NSNumber *average = [someNumbers valueForKeyPath:#"#avg.self"];
For Objective-C, I would add the Higher-Order-Functions to this list of answers: https://github.com/fanpyi/Higher-Order-Functions
#import <Foundation/Foundation.h>
typedef id (^ReduceBlock)(id accumulator,id item);
#interface NSArray (HigherOrderFunctions)
-(id)reduce:(id)initial combine:(ReduceBlock)combine;
#end
#import "NSArray+HigherOrderFunctions.h"
#implementation NSArray (HigherOrderFunctions)
-(id)reduce:(id)initial combine:(ReduceBlock)combine{
id accumulator = initial;
for (id item in self) {
accumulator = combine(accumulator, item);
}
return accumulator;
}
#end
example:
NSArray *numbers = #[#5,#7,#3,#8];
NSNumber *sum = [numbers reduce:#0 combine:^id(id accumulator, id item) {
return #([item intValue] + [accumulator intValue]);
}];
NSNumber *multiplier = [numbers reduce:#1 combine:^id(id accumulator, id item) {
return #([item intValue] * [accumulator intValue]);
}];
NSLog(#"sum=%#,multiplier=%#",sum,multiplier);
The reduce function is not standard in Objective-C. You can implement it as an extension of NSArray though.
In your case, you have an array of Int in Swift. You cannot have that in Objective-C, you need an array of NSNumber.
Here is an implementation of reduce that should work in your case:
#implementation NSArray (Helpers)
- (NSInteger)reduceInt:(NSInteger)initial combine:(NSInteger (^)(NSInteger acum, NSInteger element))block {
if (!self) {
return initial;
}
NSInteger acum = initial;
for (id element in self) {
if ([element isKindOfClass:[NSNumber class]]) {
acum = block(acum, [(NSNumber *)element integerValue]);
}
}
return acum;
}
#end
You can use it then with your array, something like this:
NSArray *a = #[#1, #2, #3];
NSInteger result = [a reduceInt:0 combine:^NSInteger(NSInteger acum, NSInteger element) {
return acum + element;
}];
how to translate reduce to ObjC (or better to say how to solve your "average problem" in Objective C) was perfectly answered by André Slotta. the swift reduce is much more than that. I will try to answer the second part of your question, how the concept works in swift
func reduce<T>(initial: T, #noescape combine: (T, Self.Generator.Element) throws -> T) rethrows -> T
Return the result
of repeatedly calling combine with an accumulated value initialized to
initial and each element of self, in turn, i.e. return
combine(combine(...combine(combine(initial, self[0]),
self[1]),...self[count-2]), self[count-1]).
let arr: Array<Int> = [1,2,3,4,5]
let sum = arr.reduce(0) { (sum, i) -> Int in
return sum + i
}
print(sum) // 15
// this is an quasi equivalent of
var sum1 = 0 // ..... reduce(0)....
arr.forEach { (elementValue) -> Void in
sum1 = sum1 + elementValue // ...{ return sum + i }
}
print(sum1) // 15 reduce function will return accumulated inital value
// reduce is part of SequenceType protocol, that is why
let arr1 = ["H","e","l","l","o"," ","w","o","r","l","d"]
let str = arr1.reduce("") { (str, s) -> String in
str + s
}
// works the same way
print(str) // "Hello world"
// let have a litle bit more complex example, to see how powerful, useful and easy to use reduce can be
let dict = arr1.reduce([:]) { (var dict, s) -> Dictionary<Int,String> in
let i = dict.count
dict.updateValue(s, forKey: i+1)
return dict
}
print(dict) // [11: "d", 10: "l", 2: "e", 4: "l", 9: "r", 5: "o", 6: " ", 7: "w", 3: "l", 1: "H", 8: "o"]
Write an NSArray extension
- (NSInteger)reduceStart:(NSInteger)start combine:(NSInteger(^)(NSInteger x, NSInteger y))combine {
for (NSNumber* n in self) {
if ([n isKindOfClass:[NSNumber class]]) {
start = combine (start, n.integerValue);
}
}
return start;
}
fix all mistakes that I made, and that's it. Just less flexible than Swift.

SceneKit : Extract data from SCNGeometryElement

I am using SceneKit, and I have an issue:
How can I extract the data from a SCNGeometryElement object ?
I use this method :
- (void)geometryElements:(SCNNode *)node {
for (int indexElement = 0; indexElement < node.geometry.geometryElementCount; indexElement++) {
SCNGeometryElement *currentElement = [node.geometry geometryElementAtIndex:indexElement];
NSLog(#"\n");
NSLog(#"bytes per index : %d", currentElement.bytesPerIndex);
NSLog(#"number element : %d", currentElement.primitiveCount);
NSLog(#"data lenght : %d", currentElement.data.length);
for (int indexPrimitive = 0; indexPrimitive < currentElement.primitiveCount; indexPrimitive++) {
int array[3];
memset(array, 0, 3);
[currentElement.data getBytes:&array range:NSMakeRange(indexPrimitive * 3, (currentElement.bytesPerIndex * 3))];
NSLog(#"currentelement : %d %d %d", array[0], array[1], array[3]);
}
}
The result is not good :
2015-04-10 15:10:25.183 IKTest[1234:244778] currentelement : 14539995 -1068223968 -379286778
2015-04-10 15:10:25.183 IKTest[1234:244778] currentelement : 14737374 -1068223968 -379286778
2015-04-10 15:10:25.183 IKTest[1234:244778] currentelement : 14934753 -1068223968 -379286778
Thanks in advance.
a few notes:
you should rely on geometryElement.primitiveType instead of hard coding 3 (unless you are sure that you're always dealing with SCNGeometryPrimitiveTypeTriangles)
it seems that the range's location does not take geometryElement.bytesPerIndex into account
your buffer is of size 3 * sizeof(int) but should be of size numberOfIndicesPerPrimitive * geometryElement.bytesPerIndex
As mnuages said, you should confirm primtive type and data type of index first.
Your code only work if index type is int.
Here is some code work for me. I only deals that geometry consisted of triangles.
void extractInfoFromGeoElement(NSString* scenePath){
NSURL *url = [NSURL fileURLWithPath:scenePath];
SCNScene *scene = [SCNScene sceneWithURL:url options:nil error:nil];
SCNGeometry *geo = scene.rootNode.childNodes.firstObject.geometry;
SCNGeometryElement *elem = geo.geometryElements.firstObject;
NSInteger componentOfPrimitive = (elem.primitiveType == SCNGeometryPrimitiveTypeTriangles) ? 3 : 0;
if (!componentOfPrimitive) {//TODO: Code deals with triangle primitive only
return;
}
for (int i=0; i<elem.primitiveCount; i++) {
void *idxsPtr = NULL;
int stride = 3*i;
if (elem.bytesPerIndex == 2) {
short *idxsShort = malloc(sizeof(short)*3);
idxsPtr = idxsShort;
}else if (elem.bytesPerIndex == 4){
int *idxsInt = malloc(sizeof(int)*3);
idxsPtr = idxsInt;
}else{
NSLog(#"unknow index type");
return;
}
[elem.data getBytes:idxsPtr range:NSMakeRange(stride*elem.bytesPerIndex, elem.bytesPerIndex*3)];
if (elem.bytesPerIndex == 2) {
NSLog(#"triangle %d : %d, %d, %d\n",i,*(short*)idxsPtr,*((short*)idxsPtr+1),*((short*)idxsPtr+2));
}else{
NSLog(#"triangle %d : %d, %d, %d\n",i,*(int*)idxsPtr,*((int*)idxsPtr+1),*((int*)idxsPtr+2));
}
//Free
free(idxsPtr);
}
}
As the original question has a Swift tag, I am posting my solution in Swift 5.
extension SCNGeometryElement {
/// Gets the `Element` vertices
func getVertices() -> [SCNVector3] {
func vectorFromData<UInt: BinaryInteger>(_ float: UInt.Type, index: Int) -> SCNVector3 {
assert(bytesPerIndex == MemoryLayout<UInt>.size)
let vectorData = UnsafeMutablePointer<UInt>.allocate(capacity: bytesPerIndex)
let buffer = UnsafeMutableBufferPointer(start: vectorData, count: primitiveCount)
let stride = 3 * index
self.data.copyBytes(to: buffer, from: stride * bytesPerIndex..<(stride * bytesPerIndex) + 3)
return SCNVector3(
CGFloat.NativeType(vectorData[0]),
CGFloat.NativeType(vectorData[1]),
CGFloat.NativeType(vectorData[2])
)
}
let vectors = [SCNVector3](repeating: SCNVector3Zero, count: self.primitiveCount)
return vectors.indices.map { index -> SCNVector3 in
switch bytesPerIndex {
case 2:
return vectorFromData(Int16.self, index: index)
case 4:
return vectorFromData(Int.self, index: index)
case 8:
return SCNVector3Zero
default:
return SCNVector3Zero
}
}
}
}
There might be a bit of an indentation problem here, but yes, it is a function inside another one. The objective is the same as the other answers. Create a buffer, define what types of numbers the buffer is going to handle, build the SCNVector3 and return the array.

Objective-C - How to get sum of Boleans?

Through the code below, I can get an output such as :
0
1
1
What I want is to output the sum of these booleans values, in my case the result will be : 2 because we have 0+1+1
The code [Update] :
-(void)markers{
CLLocationCoordinate2D tg = CLLocationCoordinate2DMake(location.latitude, location.longitude);
GMSCoordinateBounds *test = [[GMSCoordinateBounds alloc]initWithPath:path];
BOOL test3 = [test containsCoordinate:tg];
{
if (test3 == 1)
{
marker.position = CLLocationCoordinate2DMake(location.latitude, location.longitude);
}else if (test3 == 0)
{
marker.position = CLLocationCoordinate2DMake(0, 0);
}
}
}
}
Rather than sum BOOLs, which is counterintuitive, loop over whatever you are using to get the BOOL values, and if you get YES, increment a counter. This will be the number of YESs that you have.
If you have an array of BOOLs, you could just filter the array with a predicate to get the YES values and the length of the resulting array is the number of YESs that you have.
Edited to add code samples following OP comments
Incrementing a counter
NSUInteger numberOfBools = 0;
CLLocationCoordinate2D tg = CLLocationCoordinate2DMake(location.latitude, location.longitude);
GMSCoordinateBounds *test = [[GMSCoordinateBounds alloc]initWithPath:path];
if ([test containsCoordinate:tg1]) { ++numberOfBools; }
if ([test containsCoordinate:tg2]) { ++numberOfBools: }
... // other tests here;
// numberOfBools now contains the number of passing tests.
Edited Again, after the full code was added
// snipped code above here
// This is where you add the counter and initialise it to 0
NSUInteger numberOfBools = 0;
for (NSDictionary *dictionary in array)
{
// Snip more code to this point
BOOL test3 = [test containsCoordinate:tg];
{
if (test3)
{
// This is where you increment the counter
++numberOfBools;
// Snip more code to the end of the for block
}
// Now numberOfBools shows how many things passed test3
int sum = (test3 ? 1 : 0) + (testX ? 1 : 0) + (testY ? 1 : 0);
And not so weird variant:
#define BOOL_TO_INT(val) ((val) ? 1 : 0)
int sum = BOOL_TO_INT(test3) + BOOL_TO_INT(testX) + BOOL_TO_INT(testY);
You can just add BOOLs since bools are just integers. e.g. :
int sum = 0;
CLLocationCoordinate2D tg = CLLocationCoordinate2DMake(location.latitude, location.longitude);
GMSCoordinateBounds *test = [[GMSCoordinateBounds alloc]initWithPath:path];
BOOL test3 = [test containsCoordinate:tg];
//Obtain bolean values :
BOOL testX = /* other test */;
BOOL testY = /* other test */;
sum = test3 + testX + testY
This is a bad idea however, as BOOLs aren't necessarily 1 or 0. They are 0 and not 0
BOOL is just a typedef-ed char: typedef signed char BOOL; YES and NO are 1 and 0, but BOOL variable = 2 is perfectly valid
For example:
- (int) testX
{
if(inState1) return 1;
if(inState2) return 2;
else return 0;
}
BOOL textXResult = [self testX]; //Might return 2, this is still equivalent to YES.
The best solution is to iterate your BOOLs and instead count the number of YESes.
Another way to do this is to assume that if any one value is false, then the entire array is false, so, loop over the array until a false value is found, then break:
BOOL retval = true; //return holder variable
/*'boolsNumArray' is an NSArray of NSNumber instances, converted from BOOLs:
//BOOL-to-NSNumber conversion (makes 'boolsNumArray' NSArray, below)!
'[myNSArray addObject:[NSNumber numberWithBool:yourNextBOOL]]'
*/
for(NSNumber* nextNum in boolsNumArray) {
if([nextNum boolValue] == false) {
retval = false;
break;
}
}
return retval;

Resources