Skip to content

Commit c10e7ed

Browse files
committed
blog: Add 2025-07-27.md
1 parent 2ee97c9 commit c10e7ed

1 file changed

Lines changed: 185 additions & 0 deletions

File tree

blog/2025-07-27.md

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
---
2+
title: Fun in the FridaYS
3+
date: 2025-07-27
4+
draft: false
5+
authors: [ingydotnet]
6+
categories: [Summer-of-YS]
7+
edit: blog/2025-07-27.md
8+
comments: true
9+
---
10+
11+
Let's do a Fun FridaYS post on Sunday.
12+
13+
I wrote the YS one liner to open 40 random Rosetta Code tasks written in
14+
Clojure.
15+
16+
```bash
17+
$ cd RosettaCodeData
18+
$ vim $(ys -e 'sh-out("find Lang/Clojure"):lines:shuffle
19+
.mapv(fn([d] sh-out("ls $d"):lines
20+
.mapv(fn([f] say("$d/$f")))))' |
21+
grep -v '\-[0-9]' |
22+
head -40)
23+
```
24+
25+
Pretty cool, right?
26+
27+
<!-- more -->
28+
29+
30+
## Best Shuffle
31+
32+
Today's task is called [Best Shuffle](
33+
https://rosettacode.org/wiki/Best_shuffle).
34+
35+
Shuffle the characters of a string in such a way that as many of the character
36+
values are in a different position as possible.
37+
38+
A shuffle that produces a randomized result among the best choices is to be
39+
preferred.
40+
41+
A deterministic approach that produces the same sequence every time
42+
is acceptable as an alternative.
43+
44+
Display the result as follows:
45+
46+
```
47+
original string, shuffled string, (score)
48+
```
49+
50+
The score gives the number of positions whose character value did not change.
51+
52+
Test cases:
53+
```
54+
abracadabra
55+
seesaw
56+
elk
57+
grrrrrr
58+
up
59+
a
60+
```
61+
62+
## Clojure Solution
63+
64+
```clojure
65+
(defn score [before after]
66+
(->> (map = before after)
67+
(filter true?)
68+
count))
69+
70+
(defn merge-vecs [init vecs]
71+
(reduce (fn [counts [index x]]
72+
(assoc counts x (conj (get counts x []) index)))
73+
init vecs))
74+
75+
(defn frequency
76+
"Returns a collection of indices of distinct items"
77+
[coll]
78+
(->> (map-indexed vector coll)
79+
(merge-vecs {})))
80+
81+
(defn group-indices [s]
82+
(->> (frequency s)
83+
vals
84+
(sort-by count)
85+
reverse))
86+
87+
(defn cycles [coll]
88+
(let [n (count (first coll))
89+
cycle (cycle (range n))
90+
coll (apply concat coll)]
91+
(->> (map vector coll cycle)
92+
(merge-vecs []))))
93+
94+
(defn rotate [n coll]
95+
(let [c (count coll)
96+
n (rem (+ c n) c)]
97+
(concat (drop n coll) (take n coll))))
98+
99+
(defn best-shuffle [s]
100+
(let [ref (cycles (group-indices s))
101+
prm (apply concat (map (partial rotate 1) ref))
102+
ref (apply concat ref)]
103+
(->> (map vector ref prm)
104+
(sort-by first)
105+
(map second)
106+
(map (partial get s))
107+
(apply str)
108+
(#(vector s % (score s %))))))
109+
110+
(->> ["abracadabra" "seesaw" "elk" "grrrrrr" "up" "a"]
111+
(map best-shuffle)
112+
vec
113+
println)
114+
```
115+
116+
Run it:
117+
118+
```bash
119+
$ clj -M best-shuffle.clj
120+
[[abracadabra racrababaad 0] [seesaw wssaee 0] [elk kel 0] [grrrrrr rgrrrrr 5] [up pu 0] [a a 1]]
121+
```
122+
123+
124+
## Ported to YS
125+
126+
```yaml
127+
!YS-v0
128+
129+
defn main(input):
130+
say: read-string(input)
131+
.map(best-shuffle):vec
132+
133+
defn best-shuffle(s):
134+
ref =: s:group-indices:cycles
135+
prm =: concat.apply(map(partial(rotate 1) ref))
136+
ref =: concat(ref*)
137+
138+
map(vector ref prm):
139+
.sort-by(first _)
140+
.map(second)
141+
.map(partial(get s))
142+
.str(*)
143+
.call(\([s _ s.score(_)]) _)
144+
145+
defn score(before after):
146+
map(== before after)
147+
.filter(true?).#
148+
149+
defn group-indices(s):
150+
map-indexed(vector s)
151+
.merge-vecs({}):vals
152+
.sort-by(count _):reverse
153+
154+
defn cycles(coll):
155+
n =: coll.0.#
156+
cycle =: range(n):cycle
157+
coll =: concat(coll*)
158+
map(vector coll cycle):
159+
.merge-vecs([])
160+
161+
defn rotate(n coll):
162+
c =: coll.#
163+
n =: (c + n) % c
164+
concat coll.drop(n): coll.take(n)
165+
166+
defn merge-vecs(vecs init):
167+
reduce _ init vecs:
168+
fn(counts [index x]):
169+
assoc counts x:
170+
counts.$x.or([]).conj(index)
171+
```
172+
173+
and run it:
174+
175+
```bash
176+
$ ys best-shuffle.ys '["abracadabra" "seesaw" "elk" "grrrrrr" "up" "a"]'
177+
[[abracadabra racrababaad 0] [seesaw wssaee 0] [elk kel 0] [grrrrrr rgrrrrr 5] [up pu 0] [a a 1]]
178+
```
179+
180+
And [published on Rosetta Code](
181+
https://rosettacode.org/wiki/Best_shuffle#YAMLScript)!
182+
183+
<!--
184+
[[abracadabra aarcarraabbabadarcaabc 3] [seesaw esswsesaeees 0] [elk kleeee 1] [grrrrrr rgggrrrrrrrrrr 3] [up puuu 0] [a aa 1]]
185+
-->

0 commit comments

Comments
 (0)