Generating ids for a set of integers
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
When people ask about generating IDs for a set of integers, they usually mean one of two things: assign a stable compact ID to each distinct integer, or generate new unique integers for future values. Those are different problems and need different designs. This article focuses on the common mapping problem first, then covers when hashing, sequential counters, or UUID-style solutions make sense instead.
Compact IDs for an Existing Set
If you already have a set of integers and want each unique value mapped to a dense ID range such as 0..n-1, a dictionary is the simplest solution.
Example in Python:
This preserves first-seen order. The first distinct integer gets ID 0, the next distinct integer gets 1, and so on.
Sorted vs Insertion Order Mapping
Sometimes IDs should depend on numeric order rather than encounter order. In that case, deduplicate and sort first.
Choose the rule deliberately:
- insertion order gives stable IDs relative to data arrival
- sorted order gives stable IDs relative to numeric rank
Neither is universally better.
A Reusable Java Example
If your application is in Java, a LinkedHashMap is a good fit when you want stable first-seen IDs.
This is a clean approach when the mapping must be reproducible within one run or persisted externally.
When You Need IDs for Future Inserts
If new integers will keep arriving over time, the system needs a persistent mapping store, not just an in-memory map. Otherwise the same integer may receive a different ID on the next process start.
Typical options:
- keep the map in a database table
- serialize it to disk
- rebuild it from authoritative source data on startup
If the mapping is business-critical, persistence rules matter more than the choice of programming language.
Avoid Hashes Unless You Accept Collisions or Large Values
A hash function can produce a derived number from each integer, but that is not the same as a compact unique ID. Hashes can collide, and even good hashes do not guarantee a dense range.
For example, this is deterministic but not a compact ID assignment:
Use hashing only if you truly need hashing behavior, not when you need small stable identifiers.
Direct Mapping Can Already Be the Best ID
If the original integers are already unique, bounded, and acceptable for downstream systems, you may not need a second ID at all. Extra indirection adds complexity.
Examples where original integers may already be enough:
- database primary keys
- fixed numeric codes from an external standard
- compact ranges that users never see directly
Before building an ID layer, ask what problem it actually solves.
Reverse Lookup and Compression
Many systems need both directions:
- integer to assigned ID
- assigned ID back to original integer
That is easy to support with a list or reverse map.
This is especially useful for matrix indexing, graph compression, and feature encoding.
Performance Considerations
For most workloads, dictionary-based assignment is O(n) average time. Sorting first changes the cost to roughly O(n log n) but gives deterministic numeric ordering.
Performance questions usually matter only when:
- the dataset is very large
- IDs are generated repeatedly
- the mapping must be shared across services
In those cases, persistence strategy and memory usage become part of the design.
Common Pitfalls
- Using a hash when the real need is a compact one-to-one mapping.
- Forgetting to persist the mapping when IDs must remain stable across runs.
- Mixing insertion-order IDs and sorted-order IDs in different parts of the system.
- Generating a new ID every time an integer is seen instead of reusing the existing mapping.
- Adding a new ID layer even though the original integers were already suitable identifiers.
Summary
- For an existing integer set, a map from integer to sequential ID is usually the right solution.
- Decide whether IDs should follow first-seen order or sorted numeric order.
- Persist the mapping if future runs must generate the same IDs.
- Use hashes only when you really need hashing semantics, not compact identifiers.
- If the original integers already work as identifiers, do not add unnecessary mapping complexity.
Related reading
- Generating strongly-connected, uniformly-distributed, random di-graphs
- Generating suffix tree of string S2..m from suffix tree of string S1..m
- Generator expressions vs. list comprehensions
- Generic C multidimensional iterators
- Generic List - moving an item within the list
- Get a random element in single direction linked list by one time traverse
- Get a random item from a JavaScript array
- Get adjacent elements in a two-dimensional array?

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.