-
-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementing exercise binary-search #615
Conversation
What kind of Container will you use? If it is a non continious memory store (eg. a |
Does it even matter bro? Aren't you overthinking it? it's not the point to make the better possible way to search an element in an array, rather then figuring out how to implement the algorithm, even if I knew what the heck were you talking about and indeed it were a lot slower, I don't think it would matter anyway, but that's just IMHO, what do you even mean? It's going to be slow? |
Yes, it does matter. The README sells the binary search as superior while it isn't for lists, so either implement the exercise in a way that it is not using a List but some kind of Array, or don't do it at all! At least that's my opinion, but I am not a maintainer here, so at the end @exercism/haskell descides. |
@samosaara This is supposed to be an example, therefore, the implementation matters. |
PS: As far as I can remember the best possible implementations of binary search in a linked List ar O(n log n), but most are near to O(n²). In worst case (element is found at the very last possible step) you'll have copied parts of the list log n times, you have to iterate each copied slice 1 to 1.5 times on naiv implementations (first half time for the element in the middle, another half time when you need left subslice, or a full time when needing the right subslice). In a proper Array (as in a C array, meaning a continious indexed memory area), subslicing is basically a NOOP (when done correctly by the runtime) as well as indexed access does not involve itration of the full memory, but only calculating the exact point and accessing it for reading. |
Yes, they can perform better than Lists when using their |
Oh so the whole discussion was to have the best ever, swag, 1337 h@x0r, code golf, example solution, well, ok whatever I'll use sequences. Guess I missed the point, thought you guys were complaining about the exercise itself. |
@samosaara It isn't about having the best ever, thats impossible. The idea is to show when is useful to actually use a binary search algorithm, and apparently with lists it isn't. |
I'm fine with the exercise, as long as the binary search is used with a correct datatype to not suggest bad practices and sell them as a good one. |
I thought https://hackage.haskell.org/package/array-0.5.2.0/docs/Data-Array.html would have been sufficient. Wouldn't O(1) access be more suited to showing binary search than |
@petertseng I just said sequences because it is what I've used. Probably arrays work too, but I can't find where it says that the access is constant. |
If Arrays are O(1) in random reading and also can be easily sliced, then of course they are perfect for this algorithm, but I can't find a slicing accessor in the docs… |
Okay, y'all are right, https://hackage.haskell.org/package/array-0.5.2.0/docs/Data-Array.html only specifies that "a programmer may reasonably expect rapid access to the components" without specifically explaining how rapid is the rapid referred to.
Shrug. Can just keep track of the left/right index of the subarray you're searching, and thereby avoid a need to slice, just keep the same array throughout. |
Okay, so, I guess I'm not that proficient in Haskell to implement with the kinda of quality you guys are requesting, for the example, so I guess I would need help (accepting PR on my fork XD) or at least time to implement this 😅 |
@samosaara I think that you have time. And the only "challenge" here, it is to get used to Data.Array. For example you can try to implement the algorithm in Lists, as your previous intentions were. And then translate it, keeping in mind the differences between the two containers. |
Oh wait but just to be sure, I should do change the signature of the exercise itself or just convert back and forth in the example implementation? |
@samosaara Probably the first, so that the users that are going to implement this, will be forced to use a container in which this is efficient. |
exercises/binary-search/stack.yaml
Outdated
@@ -0,0 +1 @@ | |||
resolver: lts-8.21 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before I forget: I moved to lts-9.11 now so this should change too
Well, there is a problem, I cant implement one of the tests because there is no way to represent an empty Data.Array, Do I ignore it? What should I do? |
I was able to find http://mail.haskell.org/pipermail/haskell-cafe/2004-October/007098.html by asking my preferred search engine about empty arrays, but I can't say whether this information is still up to date since it is ten years old. Is it in fact out of date? |
, value = 13 | ||
, expected = Nothing | ||
} | ||
, Case { description = "nothing is included in an empty array" | ||
, input = [] | ||
, input = listArray (1, 0) [] -- There is no way to represent an empty array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore the dumb comment, there is. it is working
Actually I have doubts if I got that right, I didn't find a way to split the array itself, and the way I'm doing it there is not much of a point, because I'm just making it into lists so I can split them... Which was the whole point of this discussion, that doing that was slow. Did I miss a method or that's the way to do it? |
In general (so regardless of the language) these algorithms avoid to copy the array. The best way to do this is to pass it around as is, and provide 2 additional parameters which determine upper and lowerbound of the active subslice.
This is only a rough draft and psedo code using C-like array accessors… But it should show the overall concept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job on the array without copying.
Here's a question that I couldn't find answered in the code currently.
I saw https://github.com/exercism/problem-specifications/blob/4599c2ecbd5ff03d098b4a6eaaea0ab7dbc518db/exercises/binary-search/canonical-data.json#L73-L81 case, where you would want to have Nothing
of searching for 7 in array1
. I think that case should be added to the tests as well.
|
||
|
||
data Case a = Case { description :: String | ||
, input :: Array Int a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would indent this line two spaces further so that the comma lines up with the open bracket on the previous row.
|
||
data Case a = Case { description :: String | ||
, input :: Array Int a | ||
, value :: a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would indent this line two spaces further so that the comma lines up with the open bracket on the previous row.
same
data Case a = Case { description :: String | ||
, input :: Array Int a | ||
, value :: a | ||
, expected :: Maybe Int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would indent this line two spaces further so that the comma lines up with the open bracket on the previous row.
same
, input :: Array Int a | ||
, value :: a | ||
, expected :: Maybe Int | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would indent this line two spaces further so that the comma lines up with the open bracket on the previous row.
same except now I'm talking about the closing bracket
, expected = Nothing | ||
} | ||
] | ||
where array1 = listArray (0, 6) [1, 3, 4, 6, 8, 9, 11] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm considering whether this should go above the cases so that I can see it before I see the cases it's going to be used in. I'm not sure, so let me know what you think about it.
|
||
## Source | ||
|
||
Wikipedia [https://en.wikipedia.org/wiki/Isogram](https://en.wikipedia.org/wiki/Isogram) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why isogram?
Hello @samosaara! I went and improved on this solution in #807, since it was so close to being finished. A few complexities have been added to the track since you started this PR, so I've addressed those. Thanks for doing all the groundwork. |
On the works!