clojure: reverse with sort and without it - clojure

reverse is not working as it supposed to
user=> (reverse (list 5 7 9 0))
(0 9 7 5)
Shouldn't it return
(9 7 5 0)
However reverse works fine with sort
user=> (reverse (sort (list 5 7 9 0)))
(9 7 5 0)
Can anybody explain the behavior of first case.

No, that's what reverse is supposed to do:
Returns a seq of the items in coll in reverse order. Not lazy.
It's reverse order, not reverse sorted order.

Related

Clojure duplicate elements in sequence

I have a simple sequence of arbitrary elements that I would like to reduce over two-by-two.
In order to do that, I generate pairs with the data, but the way I do it is wrong since I need to call a function generating the data twice :
(defn gen-pairs [l]
(partition 2 (drop 1 (take l (interleave (gen-data) (gen-data))))))
How can I avoid calling gen-data twice (gen-data returns a sequence of items lazily, like range for instance) ?
Your question would be clearer if you included an example of what output you wanted, but I think that you're after partition with a step of 1:
user=> (partition 2 1 [1 2 3 4 5 6 7])
((1 2) (2 3) (3 4) (4 5) (5 6) (6 7))

opposite of list-ref? (Racket)

Is there anything which acts as the opposite of list-ref, where instead of selecting certain values to add to a list, it'll take values away from a list?
I basically want to do the following
(list 1 2 3 4 5 6 7) (list 3 6 7) -> (list 1 2 4 5)
Where the values in list two get deleted from list one. (preferred)
Since I will always start with a list that goes from 1 to n,
the second list could also represent the location/position where a number on list 1 should be deleted. (less preferred)
I'm trying to create a code which will manipulate other functions to come up with these lists, so please be clear where each list is 'mentioned' in the code, as I sometimes get confused if people use x y and z and so forth with multiple lambda, local definitions, etc.
I have something here which does the opposite of what I want and I've been trying to alter it so instead of outputting the elements of x that are on y, it gives the elements of x which are NOT on y.
(define (selection x y)
(filter (lambda (e2)
(ormap (lambda (e1) (equal? e1 e2))
y))
x))
example:
(list 1 2 3 4 5 6 7 8 9 10)
(list 2 4 6 8 10))
-> (list 2 4 6 8 10))
Anybody have any ideas on how to change the output to what I need?
It sounds like you're using lists as sets. You could instead use Racket sets, and use the set-subtract function:
#lang racket
(set-subtract (set 1 2 3 4 5 6 7)
(set 3 6 7))
;; => (set 1 2 4 5)
remove will do the trick I guess.
> (remove* (list 1 2) (list 1 2 3 2 4 5 2))
'(3 4 5)
You can read the doc here.
Here's a simple recursive function that achieves what you want:
(define remove-list-from-list (lambda (list remlist)
(cond
[(null? list) '()]
[(member (car list) remlist) (remove-list-from-list (cdr list) remlist)]
[else (cons (car list) (remove-list-from-list (cdr list) remlist))])))
Now you can use it like so:
> (remove-list-from-list (list 1 2 3 4 5 6 7) (list 3 6 7))
'(1 2 4 5)

How to use frequencies in clojure to combine same frequency and display them once?

I making a poker hands game in clojure. I have to define a function such that such that it returns the ranks in the descending order. For example: order ["2H" "3S" "6C" "5D" "4D"] should return (6 5 4 3 2). But if there is a two-pair like this: ["5H" "AD" "5C" "7D" "AS"] then it should return (14 5 7), but mine returns [14 14 7 5 5], how can I correct this? It should work in the same way for other cases of poker hands as well like for a full house it should give the rank of the three of a kind and the rank of the two of a kind. So, for this I have written:
(defn order
[hand]
"Return a list of the ranks, sorted highest first"
(let [ranks (reverse (sort (map #(.indexOf "--23456789TJQKA" %)
(map #(str (first %)) hand))))]
(if (= ranks [14 5 4 3 2])
[5 4 3 2 1]
(into [] ranks))))
I have also written all the other poker hand functions like flush?, straight? etc.
Also, I have to define another function such that it takes two orders like '(8 5 9) '(8 7 3) and returns true if the first has the larger value of the first difference, else false. Could someone please give me an idea how to do this?
Updated to show sorting by count, then rank:
(defn ->r [hand]
(let [ranks (zipmap "23456789TJKQA" (range 2 15)) ; creates a map like {\2 2, .... \A 14}
count-then-rank
(fn [x y] (compare
[(second y) (first y)]
[(second x) (first x)]))]
(->> hand
(map (comp ranks first)) ; returns the rank for each card eg: '(5 14 5 7 14)
frequencies ; returns a map of rank vs count eg: {5 2, 14 2, 7 1}
(sort count-then-rank) ; becomes a sorted list of tuples eg: '([14 2] [5 2] [7 1])
(map first)))) ; extract the first value each time eg: '(14 5 7)
For a more complete solution, you can use the frequencies to determine if you have 4 of a kind, 3 of a kind, full house etc.
Updated with more info on straight and straight flush:
For a straight, one approach is:
Extract the ranks so you would have a list like '(14 3 2 4 5)
Sort this list to get '(2 3 4 5 14)
Get the first element: 2, and the last element 14
Construct a range from 2 (inclusive) to 15 (exclusive) to get '(2 3 4 5 6 7 8 9 10 11 12 13 14)
Compare against the sorted sequence. In this case the result is false.
Retry, but first replace 14 with 1.
replace => '(1 3 2 4 5)
sort => '(1 2 3 4 5)
(range 1 6) => '(1 2 3 4 5)
This time, the range and the sorted list match, so this is a straight.
(defn straight? [cards] ; eg: ["AH" "3H" "2H" "4H" "5H"]
(let [ranks (zipmap "23456789TJKQA" (range 2 15))
ranks-only (map (comp ranks first) cards) ; eg: '(14 3 2 4 5)
ace-high (sort ranks-only) ; eg: '(2 3 4 5 14)
ace-low (sort (replace {14 1} ranks-only)) ; eg: '(1 2 3 4 5)
consecutive #(= (range (first %) (inc (last %))) %)] ; eg: (= (range 1 6) '(1 2 3 4 5))
(or (consecutive ace-high)
(consecutive ace-low))))
For a flush, simply extract all the suits, and then ensure they are all equal:
(defn flush? [cards]
(apply = (map second cards))) ; this is when suit is the second character
Now, simply combine these two boolean conditions to determine if this is a straight flush
(defn straight-flush? [cards]
(and (straight? cards) (flush? cards)))
See if you can solve 4clojure best hand puzzle, to open up a large number of different ways to tackle this. When I solved this, I used similar, but not identical functions.
Spoiler a more complete solution (using suit first "D7" instead of rank first "7D") is below
https://github.com/toolkit/4clojure-solutions/blob/master/src/puzzle_solutions/best_hand.clj
I think frequencies will get you closer to what you're looking for.
user=> (frequencies [14 14 7 5 5])
{14 2, 7 1, 5 2}
You could use this for sorting:
user=> (sort-by (frequencies [14 14 7 5 5]) [14 14 7 5 5])
(7 14 14 5 5)
And then you could use distinct:
user=> (distinct [14 14 7 5 5])
(14 7 5)
Putting all of these together should get you exactly what you want. I'll leave that as an exercise for the reader. When I'm stuck wondering if there's an easy way to do something, I often turn to Clojure's cheatsheet.

map reduce complexity

Lets suppose that i have this input: a list of list
(def list-of-list-3 (list (list 1 2 3) (list 4 5 6) (list 7 8 9)) )
(map #(reduce * %1) list-of-list3 )
The map-reduce has a O(n^2) complexity in this case?
is map-reduce translated as two nested for ?
So when i run the above example on the clojure REPL, the complexity time seems like O(n).
when i duplicate the input size ( list-of-list-6 (list (list 1 2 3) (list 4 5 6) ( list 7 8 9) (list 8 2 3) (list 9 8 1) (list 7 6 4)) ) the time increase in a linear way, not quadratic.
Can anyone say why ?
thanks in advance
It's not O(n^2), it's roughly O(n*m) where n is the no of lists and m is the length of them.
There will be other factors as well to do with the lengths of various numbers. Do it by hand and time yourself to see why!
The map-reduce has a O(n^2) complexity in this case?
Impossible to say, unless you tell us what n corresponds to in the list-of-list-3 expression.
By the way, O(n^2) or O(n*n) is quadratic complexity, not exponential complexity. Exponential complexity it O(e^n).
when i [double] the input size
( list-of-list-6 (list (list 1 2 3) (list 4 5 6) ( list 7 8 9)
(list 8 2 3) (list 9 8 1) (list 7 6 4)) )
the time increase in a linear way, not exponential.
From this, I surmise that the n is supposed to be the length of the outer list. If so, then the reduce is actually O(n) not O(n^2). To get quadratic growth, you would need to define list-of-list-6 as:
( list-of-list-6 (list (list 1 2 3 4 5 6) (list 4 5 6 1 3 2)
(list 7 8 9 1 2 3) (list 8 2 3 2 3 4)
(list 9 8 1 2 3 4) (list 7 6 4 5 6 7)) )

Scheme How to Take the first item in the List?

Say I want to take the first item of the lists '(4 3 1) '(5 6 8)
I want something like this
(first '(4 3 1) '(5 6 8))
should return me the first item
(4 3 1)
as result. Is there something like this in scheme build-in function I can call ?
car doesn't work, as it only returns me the first item inside 1 list
list-ref doesn't work, same reason above, returns me 1 item inside the list
How can I do that? if I need to write it myself this first function ?
You can use the list-ref procedure to get an element from a list, using its index, for example:
(let ((l '((4 3 1) (5 6 8))))
(list-ref l 0)) ; get the element at index 0
However if you only want the first element, you can use car:
(let ((l '((4 3 1) (5 6 8))))
(car l))
Check the snippet running here.
You can use "." in function definition to take arbitrary number of arguments.
(define (first . args) (car args))
(first '(4 3 1) '(5 6 8)) ;; => (4 3 1)
You're trying too hard:
> (define (first a b) a)
> (first '(1 2 3) '(4 5 6))
(1 2 3)
It's been a while since I used scheme, but wouldn't you need to have the lists in their own list first
(first (list '(4 3 1) '(5 6 8)))