Skip to content

Commit cddedb6

Browse files
authored
[IMPLEMENTATION] Compressor RLE (#726)
* [NEW IMPLEMENTATION] RLE compression algorithm * [FIX] Fix typo * [FIX] Suggestion added
1 parent 6fdad95 commit cddedb6

File tree

2 files changed

+234
-0
lines changed

2 files changed

+234
-0
lines changed

compression/rlecoding.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
rlecoding.go
3+
description: run length encoding and decoding
4+
details:
5+
Run-length encoding (RLE) is a simple form of data compression in which runs of data are stored as a single data value and count, rather than as the original run. This is useful when the data contains many repeated values. For example, the data "WWWWWWWWWWWWBWWWWWWWWWWWWBBB" can be compressed to "12W1B12W3B". The algorithm is simple and can be implemented in a few lines of code.
6+
author(s) [ddaniel27](https://github.com/ddaniel27)
7+
*/
8+
package compression
9+
10+
import (
11+
"bytes"
12+
"fmt"
13+
"regexp"
14+
"strconv"
15+
"strings"
16+
)
17+
18+
// RLEncode takes a string and returns its run-length encoding
19+
func RLEncode(data string) string {
20+
var result string
21+
count := 1
22+
for i := 0; i < len(data); i++ {
23+
if i+1 < len(data) && data[i] == data[i+1] {
24+
count++
25+
continue
26+
}
27+
result += fmt.Sprintf("%d%c", count, data[i])
28+
count = 1
29+
}
30+
return result
31+
}
32+
33+
// RLEdecode takes a run-length encoded string and returns the original string
34+
func RLEdecode(data string) string {
35+
var result string
36+
regex := regexp.MustCompile(`(\d+)(\w)`)
37+
38+
for _, match := range regex.FindAllStringSubmatch(data, -1) {
39+
num, _ := strconv.Atoi(match[1])
40+
result += strings.Repeat(match[2], num)
41+
}
42+
43+
return result
44+
}
45+
46+
// RLEncodebytes takes a byte slice and returns its run-length encoding as a byte slice
47+
func RLEncodebytes(data []byte) []byte {
48+
var result []byte
49+
var count byte = 1
50+
51+
for i := 0; i < len(data); i++ {
52+
if i+1 < len(data) && data[i] == data[i+1] {
53+
count++
54+
continue
55+
}
56+
result = append(result, count, data[i])
57+
count = 1
58+
}
59+
60+
return result
61+
}
62+
63+
// RLEdecodebytes takes a run-length encoded byte slice and returns the original byte slice
64+
func RLEdecodebytes(data []byte) []byte {
65+
var result []byte
66+
67+
for i := 0; i < len(data); i += 2 {
68+
count := int(data[i])
69+
result = append(result, bytes.Repeat([]byte{data[i+1]}, count)...)
70+
}
71+
72+
return result
73+
}

compression/rlecoding_test.go

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package compression_test
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/TheAlgorithms/Go/compression"
8+
)
9+
10+
func TestCompressionRLEncode(t *testing.T) {
11+
tests := []struct {
12+
name string
13+
data string
14+
want string
15+
}{
16+
{
17+
name: "test 1",
18+
data: "WWWWWWWWWWWWBWWWWWWWWWWWWBBB",
19+
want: "12W1B12W3B",
20+
},
21+
{
22+
name: "test 2",
23+
data: "AABCCCDEEEE",
24+
want: "2A1B3C1D4E",
25+
},
26+
{
27+
name: "test 3",
28+
data: "AAAABBBCCDA",
29+
want: "4A3B2C1D1A",
30+
},
31+
}
32+
33+
for _, tt := range tests {
34+
t.Run(tt.name, func(t *testing.T) {
35+
if got := compression.RLEncode(tt.data); got != tt.want {
36+
t.Errorf("RLEncode() = %v, want %v", got, tt.want)
37+
}
38+
})
39+
}
40+
}
41+
42+
func TestCompressionRLEDecode(t *testing.T) {
43+
tests := []struct {
44+
name string
45+
data string
46+
want string
47+
}{
48+
{
49+
name: "test 1",
50+
data: "12W1B12W3B",
51+
want: "WWWWWWWWWWWWBWWWWWWWWWWWWBBB",
52+
},
53+
{
54+
name: "test 2",
55+
data: "2A1B3C1D4E",
56+
want: "AABCCCDEEEE",
57+
},
58+
{
59+
name: "test 3",
60+
data: "4A3B2C1D1A",
61+
want: "AAAABBBCCDA",
62+
},
63+
}
64+
65+
for _, tt := range tests {
66+
t.Run(tt.name, func(t *testing.T) {
67+
if got := compression.RLEdecode(tt.data); got != tt.want {
68+
t.Errorf("RLEdecode() = %v, want %v", got, tt.want)
69+
}
70+
})
71+
}
72+
}
73+
74+
func TestCompressionRLEncodeBytes(t *testing.T) {
75+
tests := []struct {
76+
name string
77+
data []byte
78+
want []byte
79+
}{
80+
{
81+
name: "test 1",
82+
data: []byte("WWWWWWWWWWWWBWWWWWWWWWWWWBBB"),
83+
want: []byte{12, 'W', 1, 'B', 12, 'W', 3, 'B'},
84+
},
85+
{
86+
name: "test 2",
87+
data: []byte("AABCCCDEEEE"),
88+
want: []byte{2, 'A', 1, 'B', 3, 'C', 1, 'D', 4, 'E'},
89+
},
90+
{
91+
name: "test 3",
92+
data: []byte("AAAABBBCCDA"),
93+
want: []byte{4, 'A', 3, 'B', 2, 'C', 1, 'D', 1, 'A'},
94+
},
95+
}
96+
97+
for _, tt := range tests {
98+
t.Run(tt.name, func(t *testing.T) {
99+
if got := compression.RLEncodebytes(tt.data); !bytes.Equal(got, tt.want) {
100+
t.Errorf("RLEncodebytes() = %v, want %v", got, tt.want)
101+
}
102+
})
103+
}
104+
}
105+
106+
func TestCompressionRLEDecodeBytes(t *testing.T) {
107+
tests := []struct {
108+
name string
109+
data []byte
110+
want []byte
111+
}{
112+
{
113+
name: "test 1",
114+
data: []byte{12, 'W', 1, 'B', 12, 'W', 3, 'B'},
115+
want: []byte("WWWWWWWWWWWWBWWWWWWWWWWWWBBB"),
116+
},
117+
{
118+
name: "test 2",
119+
data: []byte{2, 'A', 1, 'B', 3, 'C', 1, 'D', 4, 'E'},
120+
want: []byte("AABCCCDEEEE"),
121+
},
122+
{
123+
name: "test 3",
124+
data: []byte{4, 'A', 3, 'B', 2, 'C', 1, 'D', 1, 'A'},
125+
want: []byte("AAAABBBCCDA"),
126+
},
127+
}
128+
129+
for _, tt := range tests {
130+
t.Run(tt.name, func(t *testing.T) {
131+
if got := compression.RLEdecodebytes(tt.data); !bytes.Equal(got, tt.want) {
132+
t.Errorf("RLEdecodebytes() = %v, want %v", got, tt.want)
133+
}
134+
})
135+
}
136+
}
137+
138+
/* --- BENCHMARKS --- */
139+
func BenchmarkRLEncode(b *testing.B) {
140+
for i := 0; i < b.N; i++ {
141+
_ = compression.RLEncode("WWWWWWWWWWWWBWWWWWWWWWWWWBBB")
142+
}
143+
}
144+
145+
func BenchmarkRLEDecode(b *testing.B) {
146+
for i := 0; i < b.N; i++ {
147+
_ = compression.RLEdecode("12W1B12W3B")
148+
}
149+
}
150+
151+
func BenchmarkRLEncodeBytes(b *testing.B) {
152+
for i := 0; i < b.N; i++ {
153+
_ = compression.RLEncodebytes([]byte("WWWWWWWWWWWWBWWWWWWWWWWWWBBB"))
154+
}
155+
}
156+
157+
func BenchmarkRLEDecodeBytes(b *testing.B) {
158+
for i := 0; i < b.N; i++ {
159+
_ = compression.RLEdecodebytes([]byte{12, 'W', 1, 'B', 12, 'W', 3, 'B'})
160+
}
161+
}

0 commit comments

Comments
 (0)