I have a very weird array and I am not sure what I am missing, something very simple I am sure. Here is my code, This code loops a struct with arrays of objects and variables and attempts to find the objects which category = 1, when this is true, it sends the array of objects into another array. Everything works fine, until I try to copy the array into the sorted array, more comments in code. I am trying to sort a tableView when the user clicks a certain category, the 4 possible categories are 1,30,31,32 (don't ask why)
var courses = [Course]()
var sortedCourses = [Course]()
#objc func catOthersButtonObj(_ sender: UIButton){ //<- needs `#objc`
var count = 0
let courseCount = courses.count
let otherCat = 1
// set count to loop the number of detected arrays
// this category looks for the number 1
print("courseCount = " + String(courseCount)) // to debug if courseCount is accurate, it is
//let noOfCat = courses.categories.count
while (count < courseCount)
{
print("count = " + String(count)) // to debug if count is increasing every loop, it is
let totalNoCat = (courses[count].categories?.count)!
var catCount = 0
// while entering a loop of arrays of objects, it searches for the array "categories" and sets totalNoCat = number of categories, this is neccesary because one object can have many categories
// catCount is used to loop through the number of detect categories
if (totalNoCat == 0)
{
break
}
// If no categories is detected, next array
while (catCount < totalNoCat)
{
print("totalNoCat = " + String(totalNoCat))
print("catCount = " + String(catCount))
// debug, check if totalNoCat is detected
// debug, catCount if number of categories is detected and added
if (courses[count].categories?[catCount] == otherCat)
{
print("category Detected = " + String((courses[count].categories?[catCount])!))
// see if category is 1, when it is 1, this is triggered, so its working fine
let currentNoSortedCourses = sortedCourses.count
print("currentNoSortedCourses = " + String(currentNoSortedCourses))
// check the number of sorted array, this is to add array into the next array
// if there is 0 number of sorted arrays, then sorted[0] should be course[detectarray category = 0 array]
//print(courses[count]) checks if courses[count] has data, it does
sortedCourses[currentNoSortedCourses] = courses[count] //where the error is
//here it is sortedCourses[0] = courses[7] ( 7 is which the array detected the correct category
break
}
catCount = catCount + 1
print("Category Detected = " + String((courses[count].categories?[catCount - 1])!))
//debug, if category not 1, show what it is
}
count = count + 1
}
}
Print results
courseCount = 50
count = 0
totalNoCat = 2
catCount = 0
Category Detected = 31
totalNoCat = 2
catCount = 1
Category Detected = 30
count = 1
totalNoCat = 2
catCount = 0
Category Detected = 31
totalNoCat = 2
catCount = 1
Category Detected = 30
count = 2
totalNoCat = 1
catCount = 0
Category Detected = 30
count = 3
totalNoCat = 2
catCount = 0
Category Detected = 32
totalNoCat = 2
catCount = 1
Category Detected = 30
count = 4
totalNoCat = 2
catCount = 0
Category Detected = 32
totalNoCat = 2
catCount = 1
Category Detected = 30
count = 5
totalNoCat = 1
catCount = 0
Category Detected = 32
count = 6
totalNoCat = 2
catCount = 0
Category Detected = 32
totalNoCat = 2
catCount = 1
Category Detected = 30
count = 7
totalNoCat = 1
catCount = 0
category Detected = 1
currentNoSortedCourses = 0
Without going much into the structure of the code and how it can be written in a more "Swifty" way, I can see the problem is that this is not a good way to append to an array in Swift.
let currentNoSortedCourses = sortedCourses.count
sortedCourses[currentNoSortedCourses] = courses[count]
This is accessing an index that is out of bounds and causes a crash. To append to an array in Swift use append method.
sortedCourses.append(courses[count])
Whilst I'm here I might as well tell you that a better way (one liner) to solve your problem probably be something like this
sortedCourses = courses.filter { $0.categories.contains(1) }
I am trying to figure out the most elegant way of converting a simple int array (e.g. {1, 2, 3}) to a simple String array (e.g. {"id", "1", "id", "2", "id", "3"}) of String pairs using Java 8 streams.
Traditionally the code looks like this: -
int[] input = {1, 2, 3};
String[] output = new String[input.length * 2];
int i = 0;
for (int val : input) {
output[i++] = "id";
output[i++] = String.valueOf(val);
}
But assuming this can be done in a 1-liner in Java 8.
String[] result = Arrays.stream(input)
.mapToObj(x -> new String[] { "id", "" + x })
.flatMap(Arrays::stream)
.toArray(String[]::new);
Or may be a bit more verbose (but worse since we are first joining, only to split immediately after)
String[] result = Arrays.stream(input)
.mapToObj(x -> "id" + "," + x)
.collect(Collectors.joining(","))
.split(",");
I can think of these two, but it's hardly more readable of what you already have in place with a simple for loop.
Can make it even less readable than Eugene's solution:
String[] output = IntStream.range(0, input.length * 2)
.mapToObj(x -> x % 2 == 0 ? "id" : input[x / 2 ] + "")
.toArray(String[]::new);
And another variation of this can be next:
String[] result = Arrays.stream( input )
.boxed()
.flatMap( x -> Stream.of( "id", Integer.toString( x ) ) )
.toArray( String[]::new );
I have an array “a” like the following:
let a = [1.0, 2.0, 10.0, 0.0, 5.0] // original array
I am looking to find the number 10.0 in “a” using binary search.
For that I sort the array to get array “asr”:
let asr = a.sorted()
print(asr)
// [0.0, 1.0, 2.0, 5.0, 10.0]
Binary search for 10.0 in “asr” will return me index = 4. Whereas I am looking for index = 2 as in the original array “a”. And I am also looking for speed since my arrays are long.
Any suggestions?
I paste below the binary search algorithm I am using:
func binarySearch<T:Comparable>(inputArr:Array<T>, searchItem: T)->Int{
var lowerIndex = 0;
var upperIndex = inputArr.count - 1
while (true) {
let currentIndex = (lowerIndex + upperIndex)/2
if(inputArr[currentIndex] == searchItem) {
return currentIndex
} else if (lowerIndex > upperIndex) {
return -1
} else {
if (inputArr[currentIndex] > searchItem) {
upperIndex = currentIndex - 1
} else {
lowerIndex = currentIndex + 1
}
}
}
}
I give example of my x (time) and y (value) arrays. For multiple such arrays, I need to find maximum of values in y and store the related unique x value.
let x = [230.0, 231.0, 232.0, 233.0, 234.0, 235.0, 236.0, 237.0, 238.0, 239.0, 240.0, 241.0, 242.0, 243.0, 244.0, 245.0, 246.0, 247.0, 248.0, 249.0, 250.0, 251.0, 252.0, 253.0, 254.0, 255.0, 256.0, 257.0, 258.0, 259.0, 260.0, 261.0, 262.0, 263.0, 264.0, 265.0, 266.0, 267.0, 268.0, 269.0, 270.0, 271.0, 272.0, 273.0, 274.0, 275.0, 276.0, 277.0, 278.0, 279.0, 280.0, 281.0, 282.0, 283.0, 284.0, 285.0, 286.0, 287.0, 288.0, 289.0, 290.0, 291.0, 292.0, 293.0, 294.0, 295.0, 296.0, 297.0, 298.0, 299.0, 300.0, 301.0, 302.0, 303.0, 304.0, 305.0, 306.0, 307.0, 308.0, 309.0, 310.0, 311.0, 312.0, 313.0, 314.0, 315.0, 316.0, 317.0, 318.0, 319.0, 320.0, 321.0, 322.0, 323.0, 324.0, 325.0, 326.0, 327.0, 328.0, 329.0, 330.0, 331.0, 332.0, 333.0, 334.0, 335.0, 336.0, 337.0, 338.0, 339.0, 340.0, 341.0, 342.0, 343.0, 344.0] // unique ascending time stamps
let y = [-0.0050202642876176198, 0.022393410398194001, 0.049790254951834603, 0.077149678828730195, 0.104451119608423, 0.131674058448602, 0.15879803550636501, 0.185802665315146, 0.21266765210574901, 0.239372805059962, 0.26589805348529699, 0.29222346189943499, 0.31832924501308402, 0.34419578259991401, 0.36980363424246498, 0.39513355394291599, 0.42016650458771598, 0.444883672255248, 0.46926648035572899, 0.49329660359275201, 0.51695598173596602, 0.54022683319452802, 0.56309166838114799, 0.58553330285668204, 0.60753487024536401, 0.62907983491101405, 0.65015200438466503, 0.67073554153427395, 0.690814976467372, 0.71037521815772098, 0.72940156578721904, 0.74787971979453605, 0.765795792622184, 0.783136319153938, 0.79988826683476, 0.816039045465632, 0.83157651666592303, 0.84648900299618601, 0.86076529673452795, 0.87439466829995904, 0.88736687431637595, 0.89967216531114802, 0.91130129304248497, 0.92224551745010597, 0.93249661322397404, 0.94204687598616199, 0.95088912808120296, 0.95901672397057403, 0.96642355522725798, 0.97310405512663301, 0.979053202830236, 0.98426652715924901, 0.98874010995489703, 0.99247058902319396, 0.99545516066186102, 0.99769158176748995, 0.99917817152138799, 0.99991381265282298, 0.99989795227872502, 0.99913060231921702, 0.99761233948865402, 0.99534430486218395, 0.99232820301815805, 0.98856630075702201, 0.98406142539766805, 0.97881696265251605, 0.97283685408292797, 0.96612559413686105, 0.95868822677099297, 0.95053034165985795, 0.94165806999482904, 0.93207807987612601, 0.92179757130129403, 0.91082427075393002, 0.89916642539671898, 0.88683279687313799, 0.87383265472251104, 0.86017576941332496, 0.84587240500008198, 0.83093331140918203, 0.81536971635963695, 0.79919331692469797, 0.78241627074072795, 0.76505118686993401, 0.74711111632382299, 0.72860954225449404, 0.70956036982116599, 0.68997791573951905, 0.66987689752174295, 0.649272422415344, 0.62817997604904996, 0.60661541079433601, 0.584594933851312, 0.56213509506794002, 0.53925277450172504, 0.51596516973324402, 0.49228978294099801, 0.46824440774739501, 0.44384711584564701, 0.41911624341769299, 0.39407037735334999, 0.36872834128103499, 0.34310918142055002, 0.31723215226859403, 0.291116702127733, 0.26478245848970899, 0.23824921328407, 0.21153690800324301, 0.18466561871516801, 0.157655540974798, 0.130526974645817, 0.10330030864392201, 0.07599600561323, 0.048634586547227202, 0.0212366153658834] // y values (could be repeating)
It is natural to express a binary search as a recursive algorithm - and usually clearer, at least when you are comfortable with recursion. How about this:
func binarySearchHelper <T:Comparable> (array: Array<T>, item:T, lower:Int, upper:Int) -> Int? {
guard lower <= upper else { return nil }
let center = (lower + upper) / 2
return array[center] == item
? center
: ((lower == center ? nil : binarySearchHelper (array: array, item: item, lower: lower, upper: center)) ??
(upper == center + 1 ? nil : binarySearchHelper (array: array, item: item, lower: center + 1, upper: upper)))
}
func binarySearch <T:Comparable> (array: Array<T>, item:T) -> Int? {
return binarySearchHelper (array: array, item: item, lower: array.startIndex, upper: array.endIndex)
}
Use another array which keeps the indexes. Like:
let indexArray = [0, 1, 2, 3, 4]
Then whenever you switch a number in your original array, switch the equivalent values in indexArray.
At the end the index array would be like:
[3, 0, 1, 4, 2]
using this you can easily get the original index.
If you send the code you are using to sort I can change the code and show you how to do it..
Another method:
You can keep a copy of your original array:
let copyArray = a.copy()
then use this to find the index of each value:
let indexOfA = copyArray.index(of: "aValue")
copyArray[indexOfA] = nil
// OR if the values are all positive
copyArray[indexOfA] = -1