Swift 3 and code converter for looping arrays reversely - swift3

I have this code which is not compatible with swift3
for var i = FCatalogIdx-1; i > -1; i -=1 {
// access items in array FCaalogArr
}
Code converter suggest converting to
for i in ((-1 + 1)...FCatalogIdx-1).reversed() {
which seems to be the the same as:
for i in (0...FCatalogIdx-1).reversed() {
Is this the closest I can get to my old code? And if so, is it recommended to use the code converter suggestion - the (-1 + 1) looks ugly, but I suspect it is to give a hint of the original c-style loop logic?

You shouldn't use the (-1+1) because that is just needlessly confusing. Also, use the half-open range operator ..< to create a range that doesn't include the final index:
for i in (0 ..< FCatalogIdx).reversed() {
}
The advantage of the half-open range operator ..< over the closed range operator ... is that it is possible to create an empty range.
Consider this example:
let n = 0
for i in 0 ..< n {
print("hello") // range is empty, so this is never printed
}
for i in 0 ... n-1 { // fatal error: Can't form Range with upperBound < lowerBound
print("hello")
}

for i in FCaalogArr.indicies.reversed() would be better assuming FCaalogIdx is the last index of the array

Related

What is the nil or "empty" countable range in Swift?

In Swift3,
let highestIndex = 7
for index in 1 ..< highestIndex {
latter(index)
}
however,
let highestIndex = 0, or anything smaller
for index in 1 ..< highestIndex {
latter(index)
}
that crashes.
So, the ..< operator is impractical in most situations.
So, perhaps, something like this ...
for index in (1 ..< highestIndex).safely() {
latter(index)
}
How would one write the extension safely ?
Or at worst just a function safely(from,to) which returns a CountableRange, or, an "empty" (?) countable range? (I don't understand if a Swift extension can "catch" an error?)
Sticking as closely to the ..< operator as possible the following would be an appropriate implementation of safely.
public func safely<Bound>(_ minimum: Bound, _ maximum: Bound) -> CountableRange<Bound> where Bound : _Strideable & Comparable, Bound.Stride : Integer {
if maximum < minimum {
return CountableRange(uncheckedBounds: (lower: minimum, upper: minimum))
}
return CountableRange(uncheckedBounds: (lower: minimum, upper: maximum))
}
let one = safely(0, 12) // CountableRange(0..<12)
let two = safely(15, 12) // CountableRange(15..<15)
one.isEmpty // false
two.isEmpty // true
You might want to consider giving the parameters better names to indicate wether or not they are inclusive / exclusive bounds, etc.
Creating an extension and adding a .safely() will not work since the bounds are checked when creating the CountableRange before the call to safely could even be done.
I am a fan of simple solutions:
let lowerIndex = 1
let higherIndex = 0
for index in lowerIndex ..< max(lowerIndex, higherIndex) {
latter(index)
}
I'm able to get this to work fine:
for index in 1 ..< 1 {
latter(index)
}
For the <1 case, I recommend something like this:
guard highestIndex > 0 else { return }
for index in 1 ..< highestIndex {
latter(index)
}

What's Swift's "fromAfter" call in array slices?

Swift 3 has upTo and through
which are noninclusive, inclusive respectively
func prefix(upTo: Int)
Returns a subsequence from the start of the collection up to, but not including, the specified position.
.
func prefix(through: Int)
Returns a subsequence from the start of the collection through the specified position.
for the other end it has from
func suffix(from: Int)
Returns a subsequence from the specified position to the end of the collection.
which seems to be inclusive
What's the non-inclusive call at the far end??
// sum the numbers before, and after, an index i...
let lo = A.prefix(upTo: i).reduce(0,+) // means noninclusive
let hi = A.suffix(from: i+1).reduce(0,+) // 'from' seems to mean inclusive
what's the call I don't know? It sucks to have to write from with +1.
There is currently no non-inclusive suffix method for for Collection types in the stdlib, but for this use case, you can readily implement your own by combining suffix(from:) with dropFirst(_:) (which, imho, better shows intent than from: idx+1), e.g.
extension Collection where SubSequence == SubSequence.SubSequence {
public func suffix(after start: Index) -> SubSequence {
return suffix(from: start).dropFirst(1)
}
}
Applied to your example (separately sum numbers before and after a given partitioning number (or, index of), not including the partitioning one):
/* in this example, invalid indices will yield a full-array sum into
lo or hi, depending on high or low index out of bounds, respectively */
func splitSum(of arr: [Int], at: Int) -> (Int, Int) {
guard at < arr.count else { return (arr.reduce(0, +), 0) }
guard at >= 0 else { return (0, arr.reduce(0, +)) }
let lo = arr.prefix(upTo: at).reduce(0, +)
let hi = arr.suffix(after: at).reduce(0, +)
return (lo, hi)
}
// example usage
let arr = [Int](repeating: 1, count: 10)
print(splitSum(of: arr, at: 4)) // (4, 5)
Leaving the subject of a non-inclusive suffix method, an alternative approach to your split sum calculation would be to use one of the split(...) methods for Collection types:
func splitSum(of arr: [Int], at: Int) -> (Int, Int) {
guard at < arr.count else { return (arr.reduce(0, +), 0) }
guard at >= 0 else { return (0, arr.reduce(0, +)) }
let sums = arr.enumerated()
.split (omittingEmptySubsequences: false) { $0.0 == at }
.map { $0.reduce(0) { $0 + $1.1 } }
guard let lo = sums.first, let hi = sums.last else { fatalError() }
return (lo, hi)
}
// example: same as above
I believe the split version is a bit more verbose, however, and also semantically poorer at showing the intent of the code.

Replacing or substituting a large number of if..else statements that have specific ranges

My input is a range of positive integer values between 0 to 200, and I have to classify each value between ranges:0-24, 25-49, 50-74, 75-99, 100-124, 125-149, 150-174 and 175-200 and then output how many values lie is what range. The values are stored in a text file(TextScores.txt) separated with commas. Here is the code.
ifstream file;
string x;
int y,j;
int count[8]={0};
j=0;
file.open("C:\\Users\\USER\\Desktop\\TestScores.txt");
while(getline(file,x,','))
{
y = stoi(x);
if(y<=24)
{
count[0]++;
}
else
if (y>=25 && y<=49)
{
count[1]++;
}
else
if (y>=50 && y<=74)
{
count[2]++;
}
else
if (y>=75 && y<=99)
{
count[3]++;
}
else
if (y>=100 && y<=124)
{
count[4]++;
}
else
if (y>=124 && y<=149)
{
count[5]++;
}
else
if (y>=150 && y<=174)
{
count[6]++;
}
else
if (y>=175 && y<=200)
{
count[7]++;
}
}
for (int i=0; i<=7; i++)
{
cout<<"Test scores between range "<<setw(3)<<j<<" to "
<<setw(3)<<j+25<<" are "<<count[i]<<endl;
j+=25;
}
Alternatives for the hefty amount of if..else statements can be:
y<=24 ? count[0]++ : y>=25 && y<=49 ? count[1]++ : y>=50 && y<=74
count[2]++ : y>=75 && y<=99 ? count[3]++ : y>=100 && y<=124 ? count[4]++ :
y>=125 && y<=149 ? count[5]++ : y>=150 && y<=174 ? count[6]++ : count[7]++;
Or switch statements. Anyone got any other suggestions?
Note: I studied a little bit of range based for loops but I don't know precisely how to go about them in this situation. If anybody knows how to apply them on the problem specified it will be appreciated. I don't want to go into O.O.P. Thanks.
Notice that your ranges are exactly 25 apart. If you perform integer division on y, you can use that to index into your count array. There is a special case for y=200 because that would return 8, which is outside of your array size.
if (y >=0 && y < 200)
++count[y/25];
else if (y == 200)
++count[7];
As Richard Hodges states in his comment, a shorter, more idiomatic way of writing this would be just:
++count[ std::min(7, y/25) ];
You will need to include the algorithm header to access this function.
Define a struct
struct limit {
int min;
int max;
};
Then an array of that
struct limit limits[] = { {0, 24} {25, 49}, {50, 74} /* and so on */ };
Then loop over the array
while(getline(file,x,','))
{
y = stoi(x);
for (int i = 0; i < sizeof(limits)/sizeof(limits[0]); i++) {
if (y >= limits[i].min && y <= limits[i].max) {
count[i]++;
}
}
}
Of course if the pairs are equidistant the array approach doesn't make sense. Go with my proposal if you need arbitrary integer ranges.
Also note that my proposal is plain C, opposed to the STL based answer from πάντα ῥεῖ.
Besides that you can use a simple mathematical solution for your task, because there are apparently fixed steps of 25 (as was mentioned in this answer), in order to create a generic solution, you could use a std::map<std::pair<int,int>,int> that holds all the possible ranges as key values and run a loop for counting:
std::map<std::pair<int,int>,int> rangeCounts =
{ { 0, 25 }, 0 ,
{ 24, 50 }, 0 ,
{ 49, 75 }, 0 ,
// ...
{ 174, 200 }, 0 ,
};
for(std::unordered_map<std::pair<int,int>,int>::iterator it = rangeCounts.begin();
it != rangeCounts.end();
++it) {
if(y > (it->first).first && y < (it->first).second)
++(it->second);
}
As a side note: Your current range delimiters look strange because of these overlapping lower and higher limits (if else cascade or not).
and I have to classify each value between ranges:0-24, 25-49, 50-74, 75-99, 100-124, 125-149, 150-174 and 175-200 and then output how many values lie is what range.
The ranges (with my example) should look like:
std::map<std::pair<int,int>,int> rangeCounts =
{ { 0, 24 }, 0 ,
{ 25, 49 }, 0 ,
{ 50, 74 }, 0 ,
// ...
{ 175, 200 }, 0 ,
};
and the range condition
if(y >= (it->first).first && y <= (it->first).second)
Note: I studied a little bit of range based for loops but I don't know precisely how to go about them in this situation.
These have nothing to do with your range check problem. A range based for() loop just allow to iterate over a containers contents based on the std::begin() and std::end() standard functions implicitely.
So a range based for loop implementation for my sample would look like
for(auto& entry : rangeCounts) {
if(y >= entry.first.first && y =< entry.first.second)
++entry.second;
}
You have a pattern in the if..else statements. You are making constant range size of 25. So, you should use the division by 25 to find the correct case to make the increment:
while(getline(file,x,','))
{
y = stoi(x);
count[y / 25]++;
}

weighted boolean value - scaling

I am not sure how to implement this, but here is the description:
Take a number as input in between the range 0-10 (0 always returning false, 10 always returning true)
Take the argument which was received as input, and pass into a function, determining at runtime whether the boolean value required will be true or false
Say for example:
Input number 7 -> (7 has a 70% chance of generating a true boolean value) -> pass into function, get the boolean value generated from the function.
This function will be run multiple times - perhaps over 1000 times.
Thanks for the help, I appreciate it.
bool func(int v) {
float f = rand()*1.0f/RAND_MAX;
float vv= v / 10.0f;
return f < vv;
}
I would say generate a random number representing a percentage (say 1 to 100) then if the random number is less then or equal to the percentage chance mark it as true, else mark it as false.
This is an interesting question! Here's what I think you should do, in pseudo code:
boolean[] booleans = new boolean[10]; //boolean array of length 10
function generateBooleans(){
loop from i = 0 to 10:
int r = random(10); //random number between 0 and 9, inclusive
if(r < i){
booleans[i] = true;
}
}
}
You can then compare the user's input to your boolean array to get the pre-determined boolean value:
boolean isTrue = booleans[userInputNumber]
Here's an idea , I'm not sure that's it's gonna be helpful;
bool randomChoice(int number){
int result =rand() % 10;
return number>=result;
}
Hope it's helpful

Unexpected result regarding comparing two pointer-related integer values in C++

I have a BST of three elements {1, 2, 3}. Its structure looks like
2
/ \
1 3
Now I try to calculate the height for each node using BSTHeight() defined below and have some problem with calculating the height of '2', which value is supposed to be 1 as the heights of '1' and '3' are defined as 0. My problem is that with direct use of heights from '2's two children (see part 2 highlighted below), its height is ALWAYS 0. However, its value is correct if I use two temporary integer variables (see part 1 highlighted below). I couldn't see any difference between the two approaches in terms of functionality. Can anyone help explain why?
void BSTHeight(bst_node *p_node)
{
if (!p_node)
return;
if (!p_node->p_lchild && !p_node->p_rchild) {
p_node->height = 0;
} else if (p_node->p_lchild && p_node->p_rchild) {
BSTHeight(p_node->p_lchild);
BSTHeight(p_node->p_rchild);
#if 0 // part 1
int lchild_height = p_node->p_lchild->height;
int rchild_height = p_node->p_rchild->height;
p_node->height = 1 + ((lchild_height > rchild_height) ? lchild_height : rchild_height);
#else // part 2
p_node->height = 1 + ((p_node->p_lchild->height) > (p_node->p_rchild->height)) ? (p_node->p_lchild->height) : (p_node->p_rchild->height);
#endif
} else if (!p_node->p_lchild) {
BSTHeight(p_node->p_rchild);
p_node->height = 1 + p_node->p_rchild->height;
} else {
BSTHeight(p_node->p_lchild);
p_node->height = 1 + p_node->p_lchild->height;
}
}
Problem lies in operator precedence. Addition binds stronger than ternary operator, hence you must surround ternary operator (?:) with brackets.
Below is the corrected version. Note that all brackets you used were superflous and I've removed them. I've added the only needed pair instead:
1 + (p_node->p_lchild->height > p_node->p_rchild->height ?
p_node->p_lchild->height : p_node->p_rchild->height);
Even better would be to use std::max (from <algorithm>) instead:
1 + std::max(p_node->p_lchild->height, p_node->p_rchild->height)