Enumerate NSArray starting at givven index searching both ways (wrap around) - ios

Example. I've got an array with 15 objects. I want to start enumerating from a given index. Say start at index 5 and then the index above, the index under, above, under etc... I do want it to wrap around.
So the order of indexes in my example would be. 5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11, 14, 12, 13
It would be great to have a method signature similar to following line, but I don't require that to approva an answer:
- (void)enumerateFromIndex:(NSUInteger)index wrapAroundAndGoBothWays:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
How can this be done? Would like to avoid copying array etc.
At this post we do it with no wrap around: Enumerate NSArray starting at givven index searching both ways (no wrap around)

Borrowing from #omz, here is the wrapping variant, which is even simpler:
#implementation NSArray (Extensions)
- (void)enumerateFromIndex:(NSUInteger)index wrapAroundAndGoBothWays:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
{
BOOL stop = NO;
NSUInteger actual = index;
for (NSUInteger i = 0; i < self.count && !stop; i++) {
actual += (2*(i%2)-1)*i;
actual = (self.count + actual)%self.count;
block([self objectAtIndex:actual], actual, &stop);
}
}
#end

This is a mathematical problem. There is a nice solution. However, it involves sorting the list of indexes in advance.
The idea is to lay the integers from 0 to 15 out on a circle and taking the elements in the order they appear on an axis.
Since doing this in ObjC is so tedious, I present the python solution:
from math import pi, cos
def circlesort(N, start):
eps = 1e-8
res = range(N)
def f(x):
return -cos(2*pi*(x-start-eps)/N)
res.sort( lambda x,y:cmp(f(x), f(y)) )
return res
then
print circlesort(15, 5)
outputs
[5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11, 14, 12, 13]
which is the desired result.
EDIT
Okay, here is a C implementation:
#include <stdlib.h>
#include <math.h>
#define sign(x) ((x)>0?1:(x)<0?-1:0)
void circlesort(int* values, int N, int start){
double f(int x)
{
return -cos(2*M_PI*((double)(x-start)-.25)/N);
}
int compare (const void * a, const void * b)
{
return sign( f(*(int*)a) - f(*(int*)b) );
}
qsort (values, N, sizeof(int), compare);
}
This will circlesort an array of integers of lenght N. Use it like this:
int i, N = 15;
int indexes[N];
for (i=0;i<N;i++)
indexes[i] = i;
circlesort(indexes, N, 5);
Now the array indexes is sorted in the desired order. Because there are nested functions, you should add -fnested-functions to the compiler flags.
EDIT 2
Considering the fact that there is a much simpler solution (see my other answer) this one is rather academic.

Related

Print the second largest number on the list

I need to print the second largest number on the list, the output from the below code is all elements in the list except the first and the last one.
What is the mistake?
void main () {
List a = [9,6,4,10,13,2,3,5];
a.sort;
for(int x in a){
for (int max in a){
for (int second_last in a){
if (x > max) {
second_last = max;
max = x;
} else if (x > second_last && x != max) {
second_last = x;
print(second_last);
}
}
}
}
}
There are a few things wrong with your code:
You're not actually sorting the list. The sort method returns a new sorted list, it doesn't sort the existing list. So you need to do:
a = a.sort;
You're iterating over the list 3 times when you only need to iterate over it once.
You're not keeping track of the second largest number, you're just printing it out as you find it.
You're not checking for duplicates. If there are duplicate numbers in the list, your code will print them out multiple times.
Here's a corrected pseudo-code
void main() {
List a = [9, 6, 4, 10, 13, 2, 3, 5];
a.sort;
int max = a[0];
int second_last = a[0];
for (int x in a) {
if (x > max) {
second_last = max;
max = x;
} else if (x > second_last && x != max) {
second_last = x;
}
}
print(second_last);
}
I need to print the second largest number on the list
Sort the array (desc).
Access the second element.
List a = [9, 6, 4, 10, 13, 2, 3, 5];
a.sort((a, z) => z - a);
// final b = a.toList()..sort(...); if you do not want to modify the original array.
print(a.take(2)); // [13, 10]
print(a.take(2)[1]); // [10]
print(a.take(2).skip(1)); // [10]
print(a.skip(1).first); // [10]
You are missing () on sort. You can do
void main() {
List a = [9, 6, 4, 10, 13, 2, 3, 5];
a.sort();
print(a[a.length - 2]); //get second large item
List b = [9, 6, 4, 10, 13, 2, 3, 5];
//or like revese sort
b.sort((a, b) => b.compareTo(a));
print(b[1]);
}
If you find a solution that is without using the sort function, and also works with all possible conditions,
so you can use this solution as well,
void main(){
var list =[9,6,4,10,13,2,3,5,13];
var secondLargest = findSecLargest(list);
print(secondLargest);
}
findSecLargest(List<int> list) {
var secLargest =-1;
var largest=list[0];
for(int i = 1 ; i < list.length ; i ++){
if(largest<list[i]){
secLargest = largest;
largest = list[i];
}else if(secLargest<list[i] && list[i]!=largest){
secLargest = list[i];
}
}
return secLargest;
}

Dart - Are sets really unordered?

From the documentation:
A set in Dart is an unordered collection of unique items.
But if I run this sample code:
final a = {0, 1, 2};
final b = {2, 1, 0};
for (final i in a) {
print('a - $i');
}
for (final i in b) {
print('b - $i');
}
print(a == b);
I get the output
a - 0
a - 1
a - 2
b - 2
b - 1
b - 0
false
The 2 iterables a and b don't behave the same when looped over and == is false (But I guess == makes sense since the a and b are not the same instance).
However, what I don't understand is if a and b are constants:
const a = {0, 1, 2};
const b = {2, 1, 0};
for (final i in a) {
print('a - $i');
}
for (final i in b) {
print('b - $i');
}
print(a == b);
This yields the same output.
And if I order b as a:
const a = {0, 1, 2};
const b = {0, 1, 2};
for (final i in a) {
print('a - $i');
}
for (final i in b) {
print('b - $i');
}
print(a == b);
It logs:
a - 0
a - 1
a - 2
b - 0
b - 1
b - 2
true
I'm a bit surprised that const a = {0, 1, 2} and const b = {2, 1, 0} are not equal. Aren't const variable being reused, and aren't a and b supposed to be equal since sets are unordered?
What am I missing?
Dart sets are ordered in the sense that if you use their iterator, you get elements in some order. That order may or may not be predictable. The order is unspecified for sets in general, but some Set implementations may choose to specify a specific ordering.
The one thing that is required is that the ordering of a set doesn't change unless the set changes. So, if you iterate the same set twice, without changing it in-between, you get the same ordering — whatever it is.
LinkedHashSet promises insertion ordering.
SplayTreeSet promises comparator ordering.
Constant set literals promise source ordering (first occurrence if the same value occurs more than once). They're like immutable LinkedHashSets.

How can I generate a unique, predictable, repeatable, non sequential alphanumeric identifier?

I have to generate identifiers composed of four alphanumerical characters, e.g. B41F.
I have the following requirements:
Each identifier must be unique (there is no central location to lookup existing identifiers)
The identifier must not be obviously sequential (e.g. 1A01, 1A02)
It must be predictable
It must be repeatable using solely the identifier index (on two different environment, the Nth identifier generated, which has index N, must be the same)
The problem is generic to any language. My implementation will be done in dart.
I think this could be done with a PRNG and some LUT, but I could not find any implementation or pseudo-code that respects requirement 4) without replaying the whole sequence. Also, some PRNG implementation have a random component that is not guaranteed to be repeatable over library update.
How can I achieve this? I'm looking for pseudo-code, code or hints.
You should not use a PRNG when identifiers must be unique. RNGs do not promise uniqueness. Some might have a long period before they repeat, but that's at their full bit-range, reducing it to a smaller number may cause conflicts earlier.
Your identifiers are really just numbers in base 36, so you need something like shuffle(index).toRadixString(36) to generate it.
The tricky bit is the shuffle function which must be a permutations of the numbers 0..36^4-1, one which looks random (non-sequential), but can be computed (efficiently?) for any input.
Since 36^4 is not a power of 2, most of the easy bit-shuffles likely won't work.
If you can live with 32^4 numbers only (2^20 ~ 1M) it might be easier.
Then you can also choose to drop O, I, 0 and 1 from the result, which might make it easier to read.
In that case, I'd do something primitive (not cryptographically secure at all), like:
// Represent 20-bit numbers
String represent(int index) {
RangeError.checkValueInInterval(index, 0, 0xFFFFF, "index");
var digits = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
return "${digits[(index >> 15) & 31]}${digits[(index >> 10) & 31]}"
"${digits[(index >> 5) & 31]}${digits[index & 31]}";
}
// Completely naive number shuffler for 20-bit numbers.
// All numbers made up on the spot.
int shuffle(int index) {
RangeError.checkValueInInterval(index, 0, 0xFFFFF, "index");
index ^= 0x35712;
index ^= index << 15;
index ^= index << 4;
index ^= index << 12;
index ^= index << 7;
index ^= index << 17;
return index & 0xFFFFF; // 20 bit only.
}
If you really want the full 36^4 range to be used, I'd probably do something like the shuffle, but in base-six arithmetic. Maybe:
String represent(int index) =>
RangeError.checkValueInInterval(index, 0, 1679615, "index")
.toRadixString(36).toUpperCase();
int shuffle(int index) {
RangeError.checkValueInInterval(index, 0, 1679615, "index");
const seed = [1, 4, 2, 5, 0, 3, 1, 4]; // seed.
var digits = List<int>.filled(8, 0);
for (var i = 0; i < 8; i++) {
digits[i] = index.remainder(6);
index = index ~/ 6;
}
void shiftAdd(List<int> source, int shift, int times) {
for (var n = digits.length - 1 - shift; n >= 0; n--) {
digits[shift + n] = (digits[shift + n] + source[n] * times).remainder(6);
}
}
shiftAdd(seed, 0, 1);
shiftAdd(digits, 3, 2);
shiftAdd(digits, 5, 1);
shiftAdd(digits, 2, 5);
var result = 0;
for (var i = digits.length - 1; i >= 0; i--) {
result = result * 6 + digits[i];
}
return result;
}
Again, this is something I made up on the spot, it "shuffles", but does not promise anything about the properties of the result, other than that they don't look sequential.

Missing numbers in nsarray

Good day, For example: If I have an nsarray [3, 1, -5, 3, 3, -5, 0, 1, 1, 3]
How do I calculate Missing numbers in my Array:
-4
-3
-2
-1
2
But - No sorting is allowed and must run in linear time O(N)
Well the brute force way would be something like this
a. find the max and min values in the array -5, 3
b. loop multiple times the array form -5 to 3 looking for the specific number (-5, -4, -3, -2, -1, 0 .... 3)
b1. if the number if found break that loop and continue with the next
b2 . if the loop ends without breaking take note of that number
It's inefficient compared to just sorting it, but it runs in a linear way
The idea is to make another array of bools and to check true if that number exist. After you do that, just go through array of bools and if number is false then its missing.
plz use this code
NSArray *a = #[#3, #1, #-5, #3, #3, #-5, #0, #1, #1, #3];
NSNumber *max=[a valueForKeyPath:#"#max.self"];
NSNumber *min=[a valueForKeyPath:#"#min.self"];
int big = [max intValue];
int small = [min intValue];
while (small<=big) {
if ([a containsObject:[NSNumber numberWithInt:small]]) {
}
else
{
NSLog(#"missing number is %d",small);
}
small++;
}
result
If the numbers in the array are consecutive integers, then 'Sort' the array and find the difference between the two consecutive numbers. If it is 1, then the number is not missed. Else, the number has missed.

Objective C: Array with size repopulate

I need an array where I can store 3 values, and calculate the average of it.
After 3s the array is full, I would like to refresh every value starting from begin [0] of the array. So every 3s the the array is updated and I have the most recent average. For the moment when I add an object the array keeps growing.
This is the code I have at the moment:
//Inside function which loops every second so I can access myValue
self.myArray = [[NSMutableArray alloc] initWithCapacity:3];
[self.myArray addObject:[NSNumber numberWithDouble:myValue]];
for(int i = 0; i < self.myArray.count; i++) {
NSLog(#"Array %d: %#", i, self.myArray[i]);
}
Output
Array 0: 2
Array 1: 4
Array 2: 5
Array 3: 6
Array 4: 1
Just check if the size of your array is larger than 3. If so, remove the oldest element.
Here is a possible implementation:
Alloc and init the array:
self.myArray = [[NSMutableArray alloc] init];
Insert a new object and delete the oldest one:
[self.myArray insertObject:object atIndex:0];
if ( self.myArray.count > 3 )
{
[self.myArray removeLastObject];
}
It looks like you're trying to calculate a running average that gets updated every second. Here's a simple alternative approach that may work for you.
Initialize the average:
runningAverage = myValue;
Inside the loop:
const int WEIGHT = 3;
runningAverage = (runningAverage * (WEIGHT - 1) + myValue) / WEIGHT;
Here's what the output would look like:
Input: 1, 2, 3, 4, 101, 6, 7, 8
(Using an array)
Output: -, -, 2, 3, 36, 37, 38, 7
(Using running average)
Output: 1, 1.33, 1.88, 2.59, 35.4, 25.6, 19.4, 15.6

Resources