cancel
Showing results for 
Search instead for 
Did you mean: 

Simple exercicio (novato)

eletrofone
New Contributor
Good evening everyone!

Unfortunately I'm not having the time I would like to study KDB + and Q.

I am at the very beginning of my studies.
Following all indications from the official website (learn section).

I'm still thinking of simple examples to solve (not from the real world).

Can someone check this simple exercise for me?
Given any list, display only items that are not repeated.
l: 1 2 4 5 7 9 2 2 5
Expected response: 1 4 7 9

My first solution:
q) where 1= count each group l
q) 1 4 7 9

I will continue to think about other solutions.
Could someone give me a more "optimized" solution?

Thank you for your help!
11 REPLIES 11

TerryLynch
New Contributor II
I imagine that your solution is the one that most people would use in practice. 

For the sake of variety:

q){x where d&1_(d:differ x),1b}asc 1 2 4 5 7 9 2 2 5
1 4 7 9

Sort the list then if an entry is different from the previous entry and different to the next it's unique. 

Terry

Or possibly more efficiently - if an entry matches the previous or matches the next in the sorted list then exclude it

q){x where not d|next d:(~':)x}asc 1 2 4 5 7 9 2 2 5
1 4 7 9

Terry

TerryLynch, thank you!

I'm still starting and for that reason I don't know many commands / functions.
I will take advantage of your examples to learn new ways to code.

Em sexta-feira, 13 de novembro de 2020 às 06:15:29 UTC-3, TerryLynch escreveu:
I imagine that your solution is the one that most people would use in practice. 

For the sake of variety:

q){x where d&1_(d:differ x),1b}asc 1 2 4 5 7 9 2 2 5
1 4 7 9

Sort the list then if an entry is different from the previous entry and different to the next it's unique. 

Terry

No problem. Thinking a little further (last one I swear!), if it's a uniform list whose elements can be compared using equals/not-equals then it simplifies to:

q){x where(x<>prev x)&x<>next x}asc 1 2 4 5 7 9 2 2 5
1 4 7 9

The other approach using differ and identical-each-prior would work for general/mixed lists too.

Terry

Couple more ways-

q)l where 1=sum l=/:l
1 4 7 9
q)r where {y*x>=y}':[s 0;1_s,last s:differ r:asc l]
1 4 7 9

-Ajay

-Ajay

another way

q){d:distinct x;d where(x bin d)=x binr d} asc l
1 4 7 9

that is a very interesting idea

to expand on TerryLynch's solution by relaxing the constraint on types we can do
a:{x where differ[x]&differ[first x; next x:asc x]}

this works with nested too
q)a (1 2;2 3; 1 2;4 5;0 0; 0 0)
2 3
4 5



Attila
New Contributor
ah, i missed that TerryLynch originally had something quite similar

interestingly the fastest solution is hand-roll the frequency collection (ie, count each group)

q)l:100000?10000

q)\ts:100 {d:distinct x;d where(x bin d)=x binr d} asc l
481 2229056

q)\ts:100 where 1=count each group l
239 4064864

q)\ts:100 {x where not d|next d:(~':)x}asc l
187 2229056

q)\ts:100 {d where 1=@[count[d]#0;(d:distinct x)?x;+;1]}l
78 2360128

q)\ts:100 {d where 1i=@[count[d]#0i;(d:distinct x)?x;+;1i]}l
68 1770400


ajay
New Contributor II

building on it you can get away with allocating new object and shorten it further.


q)\t:100 {d where (d+1)=@[d;(d:distinct x)?x;+;1]}l
67
q)\t:100 {d where 1=@[count[d]#0i;(d:distinct x)?x;+;1i]}l
69

wp
New Contributor
another version worth noting (unfortunately slightly slower on my machine):

q)\ts:100 {d:distinct x; d where (x?d)=(-1+count x)-reverse[x]?d}l

131 1442672

q)\ts:100 {d where 1i=@[count[d]#0i;(d:distinct x)?x;+;1i]}l

113 1770528


ajay
New Contributor II
Caveta, this will only work for simple integer types


Can further improve one of the earlier solutions posted by Attila, using differ only once

q)l:100000?10000
q)\ts:100 {x where differ[x]&differ[first x; next x:asc x]} l
125 3277584

q)\ts:100 {x where (1_d,last d)&d:differ[x:asc x]} l
108 2229008

-Ajay