I have opposite question for
If i have:
typedef enum {
SUNDAY = (1 << 0),
MONDAY = (1 << 1),
TUESDAY = (1 << 2),
WEDNESDAY = (1 << 3),
THURSDAY = (1 << 4),
FRIDAY = (1 << 5),
SATURDAY = (1 << 6),
} PFDateDays;
And my input is 65 for example (SUNDAY,SATURDAY) there is a clever way for etract this values from enum?
Here is my method:
-(NSMutableArray*)selectFromMyEnum {
NSMutableArray *returnArray = [[NSMutableArray alloc] init];
int myInput = 62;
NSArray *enumArray = #[#(SATURDAY),#(FRIDAY),#(THURSDAY),#(WEDNESDAY),#(TUESDAY),#(MONDAY),#(SUNDAY)];
for(NSNumber *numberInEnumArray in enumArray) {
if(myInput >= [numberInEnumArray integerValue]) {
[returnArray addObject:numberInEnumArray];
myInput -= [numberInEnumArray integerValue];
}
}
NSLog(#"%#",returnArray);
return returnArray;
}
And this is output:
(
64, //SATURDAY
1 //SUNDAY
)
So this is correct. But maybe there is method I don't know about that allow me to do this without this pointless assign enum to array etc..
Well the first thing that comes to my mind is this. Since your enum is nicely laid out for flagging you can do something like this:
Start with your highest enum value (SATURDAY) and use a bitwise and (&) to check if your value contains it. Then shift the comparison value right by 1 and repeat until your comparison value is zero.
PFDateDays comparison = SATURDAY;
//If your enum doesn't end at 1 like the above example,
//you could also use >= SUNDAY
while(((int)comparison) > 0) {
if((myVal & comparison) == comparison)
//Do what you want, this value is valid
comparison = comparison >> 1;
}
Related
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.
In what way can I refactor nested if statements like this? A condition is met, however there are some exceptions to the condition. I recognize that this starts to approach the Arrow Anti-Pattern.
Specifically, are there any dart language features that can help me refactor or re-write this code to be more clear?
Let's use "leap years" as an example:
// on every year that is evenly divisible by 4
// except every year that is evenly divisible by 100
// unless the year is also evenly divisible by 400
bool isLeapYear(int year) {
assert(!year.isNegative);
if (year % 4 == 0) {
if (year % 100 == 0) {
if (year % 400 == 0) {
return true;
}
return false;
}
return true;
}
return false;
}
You are combining boolean checks with boolean returns.
That probably means you can do it all in one expression.
I'd do:
bool isLeapYear(int year) =>
year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
(Now, if you want to optimize, then modulo, %, is more expensive than bitwise and, &, so you can also do:
bool isLeapYear(int year) =>
year & 3 == 0 && (year & 15 == 0 || year % 100 != 0);
which should be slightly more efficient. Doing & 15, aka % 16, is sufficient to detecting being a multiple of 400 if you know the number is a multiple of 100.)
For the general case, you can reverse your if branches and return early:
bool isLeapYear(int year) {
if (year % 4 != 0) return false; // Not multiple of 4.
// Year is a multiple of 4.
if (year % 100 != 0) return true; // Not multiple of 100.
// Year is a multiple 100.
return year % 400 == 0;
}
(Noticing that
if (year % 400 == 0) {
return true;
}
return false;
is the same as return year % 400 == 0;.)
Currently using Dart with gsheets_api, which don't seem to have a function to convert column letters to numbers (column index)
As an example , this is what I use with AppScript (input: column letter, output: column index number):
function Column_Nu_to_Letter(column_nu)
{
var temp, letter = '';
while (column_nu > 0)
{
temp = (column_nu - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column_nu = (column_nu - temp - 1) / 26;
}
return letter;
};
This is the code I came up for Dart, it works, but I am sure there is a more elegant or correct way to do it.
String colLetter = 'L'; //Column 'L' as example
int c = "A".codeUnitAt(0);
int end = "Z".codeUnitAt(0);
int counter = 1;
while (c <= end) {
//print(String.fromCharCode(c));
if(colLetter == String.fromCharCode(c)){
print('Conversion $colLetter = $counter');
}
counter++;
c++;
}
// this output L = 12
Do you have any suggestions on how to improve this code?
First we need to agree on the meaning of the letters.
I believe the traditional approach is "A" is 1, "Z" is 26, "AA" is 27, "AZ" is 52, "BA" is 53, etc.
Then I'd probably go with something like these functions for converting:
int lettersToIndex(String letters) {
var result = 0;
for (var i = 0; i < letters.length; i++) {
result = result * 26 + (letters.codeUnitAt(i) & 0x1f);
}
return result;
}
String indexToLetters(int index) {
if (index <= 0) throw RangeError.range(index, 1, null, "index");
const _letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (index < 27) return _letters[index - 1];
var letters = <String>[];
do {
index -= 1;
letters.add(_letters[index.remainder(26)]);
index ~/= 26;
} while (index > 0);
return letters.reversed.join("");
}
The former function doesn't validate that the input only contains letters, but it works correctly for strings containing only letters (and it ignores case as a bonus).
The latter does check that the index is greater than zero.
A simplified version base on Irn's answer
int lettersToIndex(String letters) =>
letters.codeUnits.fold(0, (v, e) => v * 26 + (e & 0x1f));
String indexToLetters(int index) {
var letters = '';
do {
final r = index % 26;
letters = '${String.fromCharCode(64 + r)}$letters';
index = (index - r) ~/ 26;
} while (index > 0);
return letters;
}
I am trying to replace an if else statement with a ternary operator
if the cost of vodka $24 return at discount price 18 (24 *.75)
This if else loop works fine and gives me the desired result but when i
try to convert it to ternary I get "expected ':'" error in xcode. What am I
doing wrong here?
ternary operator works like this
(condition) ? (executeFirst) : (executeSecond)
here is what I have:
NSUInteger cost = 24;
if (cost == 24) {
return cost *= .75);
} else {
return nil;
}
NSUInteger cost = 24;
(cost = 24) ? return cost *= .75 : return nil;
return cost;
}
Ternary operator is used to assign a value to some variable.
Use
cost = (cost == 24) ? cost * 0.75 : cost;
or:
return (cost == 24) ? cost*0.75 : cost;
Note the difference between '==' and '='. You must have made a typo or forgot about it in your code. '==' sign checks if left and right values are equal, and '=' assigns the right value to the left side (a variable).
What you want is something like:
NSUInteger cost = 24;
return (cost == 24) ? cost *= .75 : return nil;
2 things:
The first part of the ternary operator (the condition) should be a boolean, you previously had an assignment (== vs. =)
Return the result of the ternary operator.
The ternary operator has to evaluate to something (think of it as a mini function that HAS TO return a value). For the ternary condition ? one : two, you can't have statements (e.g. x = 3) at one and two; they must be expressions. So in your case it would be
return (cost == 24 ? 0.75 * cost : nil);
You should assign ternary operator value to some variable, o return it.
NSUInteger cost = 24;
cost = (cost == 24) ? cost * .75 : nil;
return cost;
Or
NSUInteger cost = 24;
return (cost == 24) ? cost * .75 : nil;
I have an NS_OPTIONS:
typedef NS_OPTIONS(NSUInteger, BrowserViewMenuOptions) {
BrowserViewMenuOptionNone = 0,
BrowserViewMenuOptionCopy = 1 << 0,
BrowserViewMenuOptionMore = 1 << 1,
BrowserViewMenuOptionShare = 1 << 2,
BrowserViewMenuOptionDelete = 1 << 3,
BrowserViewMenuOptionDownload = 1 << 4,
};
Suppose I have a value like this:
(BrowserViewMenuOptionCopy | BrowserViewMenuOptionMore | BrowserViewMenuOptionShare)
How can I enumerate it like we do for an array?
You cannot enumerate as such, as these are constant values as opposed to elements in a collection, however if the enum follows a pattern without gaps, then you can generate all the numerical values of the enum. Yours does, so:
for (unsigned i = 0; i < 5; i++) {
NSLog(#"value=%u", 1 << i);
}
In order to generate the names, you need a look-up table.