Skip to content

Commit 14cd329

Browse files
authored
A dictionary that is sorted for you lazy people
1 parent 7fb47db commit 14cd329

File tree

1 file changed

+314
-0
lines changed

1 file changed

+314
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
package struct;
2+
3+
/**
4+
* A clone of a Python dictionary in a Java class that simulates a key-value store using a hash table
5+
* implemented from scratch without using standard collections like Map.
6+
*/
7+
public class DictionarySort {
8+
private static final int SIZE = 10; // Number of buckets
9+
private Bucket[] buckets;
10+
private SortStrategy sortStrategy = SortStrategy.KEY; // Default sorting strategy
11+
12+
/**
13+
* Enum to represent sorting strategies.
14+
*/
15+
public enum SortStrategy {
16+
KEY, VALUE
17+
}
18+
19+
/**
20+
* Inner class to represent a key-value pair.
21+
*/
22+
private static class Entry {
23+
String key;
24+
Object value;
25+
26+
Entry(String key, Object value) {
27+
this.key = key;
28+
this.value = value;
29+
}
30+
}
31+
32+
/**
33+
* Inner class to represent a bucket in the hash table.
34+
*/
35+
private static class Bucket {
36+
Entry entry;
37+
Bucket next;
38+
39+
Bucket(Entry entry) {
40+
this.entry = entry;
41+
this.next = null;
42+
}
43+
}
44+
45+
/**
46+
* Constructs an empty dictionary.
47+
*/
48+
public DictionarySort() {
49+
this.buckets = new Bucket[SIZE];
50+
}
51+
52+
/**
53+
* Constructs a dictionary with initial key-value pairs.
54+
*
55+
* @param keyValuePairs An even number of arguments where each pair consists of a key and a value.
56+
* @throws IllegalArgumentException if the number of arguments is odd.
57+
*/
58+
public DictionarySort(Object... keyValuePairs) {
59+
this();
60+
if (keyValuePairs.length % 2 != 0) {
61+
throw new IllegalArgumentException("Key-value pairs must be even.");
62+
}
63+
for (int i = 0; i < keyValuePairs.length; i += 2) {
64+
String key = (String) keyValuePairs[i];
65+
Object value = keyValuePairs[i + 1];
66+
put(key, value);
67+
}
68+
}
69+
70+
/**
71+
* Computes the index in the hash table for a given key.
72+
*
73+
* @param key The key for which the index is computed.
74+
* @return The index in the hash table.
75+
*/
76+
private int getIndex(String key) {
77+
return Math.abs(key.hashCode()) % SIZE;
78+
}
79+
80+
/**
81+
* Adds or updates a key-value pair in the dictionary.
82+
*
83+
* @param key The key to be added or updated.
84+
* @param value The value associated with the key.
85+
*/
86+
public void put(String key, Object value) {
87+
int index = getIndex(key);
88+
Bucket bucket = buckets[index];
89+
90+
// Traverse the bucket to find if the key already exists
91+
while (bucket != null) {
92+
if (bucket.entry.key.equals(key)) {
93+
// Update the value if the key is found
94+
bucket.entry.value = value;
95+
return;
96+
}
97+
bucket = bucket.next;
98+
}
99+
100+
// If key is not found, add a new entry to the beginning of the bucket
101+
Bucket newBucket = new Bucket(new Entry(key, value));
102+
newBucket.next = buckets[index];
103+
buckets[index] = newBucket;
104+
}
105+
106+
/**
107+
* Retrieves the value associated with a given key.
108+
*
109+
* @param key The key whose value is to be retrieved.
110+
* @return The value associated with the key, or null if the key is not found.
111+
*/
112+
public Object get(String key) {
113+
int index = getIndex(key);
114+
Bucket bucket = buckets[index];
115+
116+
// Traverse the bucket to find the key
117+
while (bucket != null) {
118+
if (bucket.entry.key.equals(key)) {
119+
return bucket.entry.value;
120+
}
121+
bucket = bucket.next;
122+
}
123+
return null; // Return null if the key is not found
124+
}
125+
126+
/**
127+
* Removes the key-value pair associated with the given key.
128+
*
129+
* @param key The key to be removed.
130+
*/
131+
public void remove(String key) {
132+
int index = getIndex(key);
133+
Bucket bucket = buckets[index];
134+
Bucket prev = null;
135+
136+
// Traverse the bucket to find the key
137+
while (bucket != null) {
138+
if (bucket.entry.key.equals(key)) {
139+
if (prev == null) {
140+
// Removing the first bucket in the slot
141+
buckets[index] = bucket.next;
142+
} else {
143+
// Removing a bucket from the middle or end
144+
prev.next = bucket.next;
145+
}
146+
return;
147+
}
148+
prev = bucket;
149+
bucket = bucket.next;
150+
}
151+
}
152+
153+
/**
154+
* Checks if the dictionary contains the specified key.
155+
*
156+
* @param key The key to check for.
157+
* @return true if the dictionary contains the key, false otherwise.
158+
*/
159+
public boolean containsKey(String key) {
160+
int index = getIndex(key);
161+
Bucket bucket = buckets[index];
162+
163+
// Traverse the bucket to find the key
164+
while (bucket != null) {
165+
if (bucket.entry.key.equals(key)) {
166+
return true;
167+
}
168+
bucket = bucket.next;
169+
}
170+
return false;
171+
}
172+
173+
/**
174+
* Sets the sorting strategy for the dictionary.
175+
*
176+
* @param strategy The sorting strategy to use.
177+
*/
178+
public void setSortStrategy(SortStrategy strategy) {
179+
this.sortStrategy = strategy;
180+
}
181+
182+
/**
183+
* Returns a string representation of the dictionary in a JSON-like format without formatting.
184+
*
185+
* @return A JSON-like string representation of the dictionary.
186+
*/
187+
@Override
188+
public String toString() {
189+
return toString(false);
190+
}
191+
192+
/**
193+
* Returns a string representation of the dictionary in a JSON-like format with optional formatting.
194+
*
195+
* @param formatted If true, returns the string in a formatted JSON-like format.
196+
* @return A JSON-like string representation of the dictionary.
197+
*/
198+
public String toString(boolean formatted) {
199+
StringBuilder sb = new StringBuilder();
200+
sb.append(formatted ? "{\n" : "{");
201+
202+
Entry[] entries = getAllEntries();
203+
if (sortStrategy == SortStrategy.KEY) {
204+
sortByKey(entries);
205+
} else if (sortStrategy == SortStrategy.VALUE) {
206+
sortByValue(entries);
207+
}
208+
209+
boolean first = true;
210+
for (Entry entry : entries) {
211+
if (!first) {
212+
sb.append(formatted ? ",\n" : ", ");
213+
}
214+
sb.append(formatted ? " " : "")
215+
.append("\"").append(entry.key).append("\": ")
216+
.append("\"").append(entry.value.toString()).append("\"");
217+
first = false;
218+
}
219+
sb.append(formatted ? "\n}" : "}");
220+
return sb.toString();
221+
}
222+
223+
/**
224+
* Retrieves all entries from the dictionary.
225+
*
226+
* @return An array of all entries.
227+
*/
228+
private Entry[] getAllEntries() {
229+
// Gather all entries from all buckets
230+
int count = 0;
231+
for (Bucket bucket : buckets) {
232+
while (bucket != null) {
233+
count++;
234+
bucket = bucket.next;
235+
}
236+
}
237+
238+
Entry[] entries = new Entry[count];
239+
int index = 0;
240+
for (Bucket bucket : buckets) {
241+
while (bucket != null) {
242+
entries[index++] = bucket.entry;
243+
bucket = bucket.next;
244+
}
245+
}
246+
return entries;
247+
}
248+
249+
/**
250+
* Sorts entries by key using quicksort.
251+
*
252+
* @param entries The array of entries to be sorted.
253+
*/
254+
private void sortByKey(Entry[] entries) {
255+
quickSort(entries, 0, entries.length - 1, true);
256+
}
257+
258+
/**
259+
* Sorts entries by value using quicksort.
260+
*
261+
* @param entries The array of entries to be sorted.
262+
*/
263+
private void sortByValue(Entry[] entries) {
264+
quickSort(entries, 0, entries.length - 1, false);
265+
}
266+
267+
/**
268+
* Quicksort implementation to sort entries by key or value.
269+
*
270+
* @param entries The array of entries to be sorted.
271+
* @param low The starting index.
272+
* @param high The ending index.
273+
* @param byKey True to sort by key, false to sort by value.
274+
*/
275+
private void quickSort(Entry[] entries, int low, int high, boolean byKey) {
276+
if (low < high) {
277+
int pivotIndex = partition(entries, low, high, byKey);
278+
quickSort(entries, low, pivotIndex - 1, byKey);
279+
quickSort(entries, pivotIndex + 1, high, byKey);
280+
}
281+
}
282+
283+
/**
284+
* Partition method for quicksort.
285+
*
286+
* @param entries The array of entries to be partitioned.
287+
* @param low The starting index.
288+
* @param high The ending index.
289+
* @param byKey True to sort by key, false to sort by value.
290+
* @return The index of the pivot element.
291+
*/
292+
private int partition(Entry[] entries, int low, int high, boolean byKey) {
293+
Entry pivot = entries[high];
294+
int i = low - 1;
295+
for (int j = low; j < high; j++) {
296+
boolean condition;
297+
if (byKey) {
298+
condition = entries[j].key.compareTo(pivot.key) < 0;
299+
} else {
300+
condition = entries[j].value.toString().compareTo(pivot.value.toString()) < 0;
301+
}
302+
if (condition) {
303+
i++;
304+
Entry temp = entries[i];
305+
entries[i] = entries[j];
306+
entries[j] = temp;
307+
}
308+
}
309+
Entry temp = entries[i + 1];
310+
entries[i + 1] = entries[high];
311+
entries[high] = temp;
312+
return i + 1;
313+
}
314+
}

0 commit comments

Comments
 (0)