Skip to content

Collections Are the Best, Here Is Why You Should Use Them

Learn to learn code faster, using techniques honed by years of study, neatly packaged into one book: How to Learn Code

Collections are very similar across the different programming languages. They involve the same data structures, the same functions and essentially look the same in every language.

If you are learning collections, just know you are learning it for all languages so be encouraged about learning these data types.

In every language they are a library of data structures used in every day programming. They are called collections because each data structure is a collection of objects. These collections manipulate memory in a certain way. They are implementations of stacks, queues, maps, lists, etc, given to you for your convenience. 

The way you manipulate memory is structured by its collection type. A stack for example is LIFO (Last-In-First-Out). Let’s look at this in Java:

import java.util.Stack;

Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(stack.pop()); // Outputs 3

The key part, stack already exists in the collections library. java.util.* has all the collections inside it. You do not have to implement any collections. They come with the functions and inner data structures. They are meant to make your problem solving easier. 

Let’s look at one more, Maps:

import java.util.HashMap;
import java.util.Map;

Map<String, Integer> map = new HashMap<>();
map.put("Alice", 30);
map.put("Bob", 25);
map.put("Charlie", 35);
System.out.println("Age of Bob: " + map.get("Bob")); // Outputs 25

You place three numbers in three different keys from String to Integer. You do not implement the data structure, you just import it.

In the background these collections are wrappers of primitives. If you look inside the data structure you will see an int[] array, or a String[] array. Basic primitives.

This is impossible to avoid as all custom classes are simply wrappers for primitives, no matter what you implement.

Why use collections?

Collections make you more efficient, need less code and are convenient for the programmer. The reason, these data structures are meant to be used with custom classes. If you make say the Coordinate class,

public class Coordinate {
    private int x;
    private int y;

    public Coordinate(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public static void main(String[] args) {
        Coordinate point = new Coordinate(3, 4);
        Coordinate point2 = new Coordinate(6, 7);
        Coordinate point3 = new Coordinate(4, 5);
        Map<String, Coordinate> map = new HashMap<>();
        map.put("Alice", point);
        map.put("Bob", point2);
        map.put("Charlie", point3);
    }
}

You can add it to any collection data structure. This is where all the power of collections comes from. You can use either primitives or custom classes, organizing and storing in an optimal way.

On the lowest level though, there is some bloat to these data structures. They cost a little more memory and processing power than the primitive versions of the data structures.

Meaning a List in C# is more bloated both in memory and processing than an array. What we sacrifice we more than make up for in the ease of making applications for the programmer.

Types of Collections

These would be considered part of programming fundamentals. They are standard in each language. It is always good practice to use these collections for your applications.

Lists

A List is a mutable string of objects. Remember we can place any class here, including primitives. Let’s look at it in C#:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Create a new List of integers
        List<int> numbers = new List<int>();

        // Add elements to the List
        numbers.Add(1);
        numbers.Add(2);
        numbers.Add(3);
        numbers.Add(4);
        numbers.Add(5);

        // Access elements by index
        Console.WriteLine("Second element: " + numbers[1]);
    }
}

We have basically an array [1, 2, 3, 4, 5]. There really is no difference between an array and a list.

The Collection, list, just includes functions which wrap around the array. Take a look:

class Program
{
    static void Main()
    {
      List<int> list = new List<int>();
      int index = 3;
      int item = 5;
      list.RemoveAt(index);
      list.Insert(index, item);
      list.Clear();
      list.Contains(item);
      list.IndexOf(item);
      list.Count;
      list.Sort();
      list.Reverse();
      //etc.
    }
}

Primitive arrays do not come with those functions. Yes Lists are simply arrays, but they are arrays with functions.

Sets

Sets are a collection of elements which are unique. They are a List, except there are no duplicate elements. In Sets we limit the functions to only those which are hash-able. This allows the data structure to map each element in the data structure.

Lets look at an example:

import java.util.HashSet;
import java.util.Set;

public static void main(String[] args) {
   Set<String> set = new HashSet<>();
   set.add("Apple");
   set.add("Banana");
   set.add("Orange");
   set.remove("Banana");
   boolean containsOrange = set.contains("Orange");
}

The power behind sets is where that add and remove banana is actually mapped. There are fewer functions for Sets than Lists, but this is done intentionally. It is a dictionary in the background. If you know your elements are going to be unique, then that is the moment to use a Set.

This means less processing and less memory usage.

Maps

These are dictionaries. You get key-value pairs for the fastest processing possible. You call a value by its key, AKA its name, so you do not have to iterate over the entire data structure.

Lets look at an example:

#include <iostream>
#include <map>

int main() {
    // Create a map of string keys and int values
    std::map<std::string, int> ageMap;

    // Insert key-value pairs into the map
    ageMap["Alice"] = 30;
    ageMap["Bob"] = 25;
    ageMap["Charlie"] = 35;

    // Access a value by its key
    std::cout << "Age of Bob: " << ageMap["Bob"] << std::endl;
}

We call “Bob” as the number 25. So whenever we ask for “Bob” in the age map we get 25 the quickest possible. The main feature of maps is how huge we can make the entire data structure and still only have O(1) or just 1 super fast function call for its value, like 25.

Queue

Queues are a First-In-First-Out data structure. They are meant for any type of waiting line in processing. They are used everywhere in programming. However nowadays people just use Lists and only use the queue-like functions.

Here is an example of a Queue:

import java.util.LinkedList;
import java.util.Queue;

public static void main(String[] args) {
    // Create a new LinkedList as a Queue
    Queue<String> queue = new LinkedList<>();

    // Add elements to the queue
    queue.offer("Apple");
    queue.offer("Banana");
    queue.offer("Orange");

    // Peek at the head of the queue without removing it
    System.out.println("Head of the queue: " + queue.peek());

    // Remove and return the head of the queue
    System.out.println("Removed from the queue: " + queue.poll());
}

Stack

Stacks are in essence the same as queues except it is Last-In-First-Out. Instead of getting the beginning of the list, we get the end.

Like said before most people just use the List data structure but use the stack-like functions. 

Here is how it looks:

#include <iostream>
#include <stack>

int main() {
    // Create a stack of integers
    std::stack<int> stack;

    // Push elements onto the stack
    stack.push(1);
    stack.push(2);
    stack.push(3);

    // Access the top element of the stack
    std::cout << "Top of the stack: " << stack.top() << std::endl;
}

Choosing the right type

Choosing the right type of Collection is a chicken and egg problem. You need to have used the data structures in the past to know what Collection to use right now.

I recommend experimenting with the different collections. Take the descriptions I gave you above and use them. It is good to use them wrongly and realize it was wrong later. Fix the error and learn a way not to use that data structure.

The best learning methods are trial and error, reading other peoples code, having your code reviewed and solving LeetCode problems.

As you learn all the ways collections are used you develop an instinct for data structures. You eventually will be able to just look at a problem and quickly know which data structure to use. Other people’s code can help clarify that instinct and code reviews will be teaching moments for your own code.

Lastly, You will be surprised how dependent LeetCode is on Collections. The problem descriptions always ask for a specific Collection to be used. LeetCode problems are a great way to figure out when and when not to use data structures.

Anywho, I hope you learned something…

CTA: Check out my book on learning code

Happy coding!

Resources

Programming fundamentals: https://jessenerio.com/why-coding-fundamentals-are-important-questions-you-should-be-asking/

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts

Search this blog

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors

Newsletter

Subscribe now to get my library of freebies + weekly emails with coding, tips for learning, and resource tips.

Learn to learn code faster, using techniques honed by years of study, neatly packaged into one book: How to Learn Code

Top content