Questions about select-keys function [duplicate] - clojure

This question already has answers here:
How to get a clojure array-map to maintain insertion order after assoc?
(1 answer)
How to reorder a map in Clojure?
(2 answers)
Closed 5 years ago.
Ideally,select-keys returns a map with keys in the order of the key seq vector. But I find that it happens only when the number of your keys is less than 10
(def params {:resource-total-calls-abandoned 1, :resource-idle-time 5, :date "2016-12-31", :resource-wrap-up-time 1, :agent-talk-time 1, :resource-work-offers 3, :aux-in-time 1, :user-id 2183, :resource-not-ready-time 3, :split 1, :aux-out-time 1, :resource-logged-in-time 1, :hold-time 115, :acd-calls 1})
(select-keys params [:user-id
:date
:split
:resource-logged-in-time
:agent-talk-time
:resource-wrap-up-time
:hold-time
:acd-calls
:resource-total-calls-abandoned
])
Here is my result:
{:user-id 2183, :date "2016-12-31", :split 1, :resource-logged-in-time 1, :agent-talk-time 1, :resource-wrap-up-time 1, :hold-time 115, :acd-calls 1, :resource-total-calls-abandoned 1}
If I have more than 10 keys to be selected from a huge map , the order of the map will be different from the order of keys
(select-keys params [:user-id
:date
:split
:resource-logged-in-time
:agent-talk-time
:resource-wrap-up-time
:hold-time
:acd-calls
:resource-total-calls-abandoned
:aux-in-time
])
The result will be different :
{:resource-total-calls-abandoned 1, :date "2016-12-31", :resource-wrap-up-time 1, :agent-talk-time 1, :aux-in-time 1, :user-id 2183, :split 1, :resource-logged-in-time 1, :hold-time 115, :acd-calls 1}
Any other ideas about returning a map with keys in the order of the keyseq vector no matter how many keys you want to select ?

If you want an associative structure with order, there is a sorted-map that maintains the order of its elements. An off-the-cuff solution could be to first select the keys that you want, and then put them in a new sorted map.
(def k [:user-id
:date
:split
:resource-logged-in-time
:agent-talk-time
:resource-wrap-up-time
:hold-time
:acd-calls
:resource-total-calls-abandoned
:aux-in-time])
(->> (select-keys params k)
(into (sorted-map-by #(< (.indexOf k %1) (.indexOf k %2)))))
The comparator function #(< ... above is just an example; if you create a sorted map this way, updates to it (e.g., assoc) will most definitely do the wrong thing. The reason is that the index in vector k is used to compare the order of elements, but it is -1 for any element not in the vector.
A more efficient solution could be to reduce over the map into a sorted data structure.
Update: As suggested by #leetwinski, changed apply to into, which removes the need to flatten the map after select-keys.

Related

How to consolidate a list of coordinates into subgroup if they are close to each within 2 or less unit distance in x direction?

I have a list(a) of coordinates as follow.
list a = {{1 2} {5 6} {1 5} {5 8} {1 8}}
I would like the result to be broken into two lists, b and c. How do I do it in tcl?
list b = {{1 2} {1 5} {1 8}}
list c = {{5 6} {5 8}}
One way, which returns a list of lists you can break up into individual variables or do whatever else is needed:
#!/usr/bin/env tclsh
# Return a list of lists of coords. Each sublist is of coordinates with
# an x value $distance or less units away from each other.
# Each coordinate will only appear once in the result.
proc partition {coords {distance 2}} {
set groups {}
foreach coord $coords {
set found false
for {set n 0} {$n < [llength $groups]} {incr n} {
if {abs([lindex $groups $n 0 0] - [lindex $coord 0]) <= $distance} {
lset groups $n [linsert [lindex $groups $n] end $coord]
set found true
break
}
}
if {!$found} {
lappend groups [list $coord]
}
}
return $groups
}
set coords {{1 2} {5 6} {1 5} {5 8} {1 8}}
foreach group [partition $coords] {
puts $group
}
when run outputs
{1 2} {1 5} {1 8}
{5 6} {5 8}
Basically, for each element of the input list, see if its first number is <= 2 of an existing element of the output list of lists, and if so, add it to that sublist. If there are no matches, append a new sublist to the result.

Removing elements that have consecutive dupes in Elixir list

I have a list of numbers in Elixir, and I want to remove the duplicates, but only for the consecutive dupes.
For the following input list: [1,1,2,2,1,1,1,1,3,3,2,2].
The result should be: [1,2,1,3,2].
Enum.dedup/1 does exactly what you want: it replaces consecutive duplicate elements with only one instance of it and returns the remaining elements in a list.
iex(1)> Enum.dedup([1, 1, 2, 2, 1, 1, 1, 1, 3, 3, 2, 2])
[1, 2, 1, 3, 2]
This works on all values that compare equal with ===, including maps:
iex(2)> Enum.dedup([%{a: 1}, %{a: 2}, %{a: 2}, %{a: 2}])
[%{a: 1}, %{a: 2}]

python: repeating elements in a list based a predicateHow

I'd like to repeat elements of a list based on a predicate.
I tried using the module itertools and a list comprehension
abc = [1,2,3,4,5,6,7,8,9]
result = [ repeat(item,2) if item==3 or item==7 else item for item in abc ]
This doesn't fail at runtime, but the resulting object is not 'flattened'
If I print it, I see
[1, 2, repeat(3, 2), 4, 5, 6, repeat(7, 2), 8, 9]
Is it doable with a list comprehension?
Thanks
This works:
from itertools import repeat
abc = [1,2,3,4,5,6,7,8,9]
result = [x for y in (repeat(item,2) if item==3 or item==7 else [item] for item in abc)
for x in y]
>>> result
[1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9]
The trick here is to put item in its own list [item] and than flatten the now consistently nested list.
to improve readability, put it in two lines:
nested_items = (repeat(item,2) if item==3 or item==7 else [item] for item in abc)
result = [item for nested_item in nested_items for item in nested_item]
Since nested_items is an iterator, there is no extra list created her.

Finding similar sets with clojure's core.logic / minikanren

this is my first question on Stack Overflow.
I’m new to logic programming and are trying to evaluate if it can be used to solve some matching problems I’m working on.
Problem:
Lets say we have a set A that looks like this.
A = {1, 2, 3, 4}
And then we have some other sets that looks like this.
B = {1, 2}
C = {3, 5, “banana"}
D = {2, 3, 4}
The problem I’m trying to solve is,
"Find me the set that share the most members with set A, compared to the other sets we know about."
The answer in this case should be set D, because it shares three members with set A. Compared to the other sets that only share two and one member with A.
Question 1:
Can Logic Programming solve this types of problems?
Question 2:
If it can, how would you do it in for example Clojure’s core.logic?
Qeshi
The following shows getting the best fit result using clojure.set:
(ns
sample.sandbox
(:require [clojure.set :as set])
)
(def A #{ 1, 2, 3, 4})
(def B #{1, 2})
(def C #{3, 5, "banana"})
(def D #{2, 3, 4})
(defn best-fit-set
[control & sets]
(apply max-key count (map #(set/intersection control %) sets )))
(best-fit-set A B C D) => #{4 3 2}

Neat extraction of elements in nested lists (Mathematica)

This is a question about rearranging parts of nested lists in Mathematica.
I've got a nested List:
DatenList = {{1, {100, 200}}, {2, {101, 201}}, {3, {102, 202}}};
and want to get another list like
{{1,100},{2,101}}
Is there a neater way than
temp = DatenList[[1 ;; 2, 1]];
temp2 = DatenList[[1 ;; 2, 2]][[;; , 1]];
temp = {temp}~Join~{temp2};
finalList = Transpose[temp]
which yields
{{1, 100}, {2, 101}}
temp2 = DatenList[[1 ;; 2, 2]][[;; , 1]]
can be written shorter as
temp2 = DatenList[[1 ;; 2, 2, 1]]
Otherwise, the whole operation can be done several ways :-
finalList = {#1, First[#2]} & ### DatenList[[1 ;; 2]]
finalList = DatenList[[1 ;; 2]] /. {a_Integer, {b_, _}} :> {a, b}
finalList = Replace[DatenList[[1 ;; 2]], {a_, {b_, _}} :> {a, b}, 1]
finalList = MapThread[{#1, First[#2]} &, Transpose[DatenList[[1 ;; 2]]]]