Event Emitter

Medium Real-World Scenarios
Implement a pub/sub event emitter with on / off / emit — the pattern behind app-wide events and notifications. Subscriptions return an id so a single listener can be removed.

Sample input

on("greet", hello); on("greet", hi); emit("greet","Alice"); off greet1; emit("greet","Bob")

Sample output

Hello Alice Hi Alice Hi Bob

Solution

class EventEmitter:
    def __init__(self):
        self.listeners = {}
        self.next_id = 0

    def on(self, event, callback):
        self.next_id += 1
        self.listeners.setdefault(event, []).append((self.next_id, callback))
        return self.next_id

    def off(self, event, sub_id):
        if event in self.listeners:
            self.listeners[event] = [(i, cb) for (i, cb) in self.listeners[event] if i != sub_id]

    def emit(self, event, arg):
        for (_, cb) in self.listeners.get(event, []):
            cb(arg)

emitter = EventEmitter()
id1 = emitter.on("greet", lambda name: print("Hello " + name))
emitter.on("greet", lambda name: print("Hi " + name))
emitter.emit("greet", "Alice")
emitter.off("greet", id1)
emitter.emit("greet", "Bob")
class EventEmitter {
  constructor() {
    this.listeners = {};
    this.nextId = 0;
  }
  on(event, callback) {
    const id = ++this.nextId;
    (this.listeners[event] = this.listeners[event] || []).push({ id, callback });
    return id;
  }
  off(event, id) {
    if (this.listeners[event]) {
      this.listeners[event] = this.listeners[event].filter(l => l.id !== id);
    }
  }
  emit(event, arg) {
    (this.listeners[event] || []).forEach(l => l.callback(arg));
  }
}

const emitter = new EventEmitter();
const id1 = emitter.on("greet", name => console.log("Hello " + name));
emitter.on("greet", name => console.log("Hi " + name));
emitter.emit("greet", "Alice");
emitter.off("greet", id1);
emitter.emit("greet", "Bob");
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

public class Main {
    static class EventEmitter {
        static class Listener {
            int id;
            Consumer<String> cb;
            Listener(int id, Consumer<String> cb) { this.id = id; this.cb = cb; }
        }
        Map<String, List<Listener>> listeners = new HashMap<>();
        int nextId = 0;
        int on(String event, Consumer<String> cb) {
            int id = ++nextId;
            listeners.computeIfAbsent(event, k -> new ArrayList<>()).add(new Listener(id, cb));
            return id;
        }
        void off(String event, int id) {
            if (listeners.containsKey(event)) {
                listeners.get(event).removeIf(l -> l.id == id);
            }
        }
        void emit(String event, String arg) {
            for (Listener l : listeners.getOrDefault(event, new ArrayList<>())) {
                l.cb.accept(arg);
            }
        }
    }

    public static void main(String[] args) {
        EventEmitter emitter = new EventEmitter();
        int id1 = emitter.on("greet", name -> System.out.println("Hello " + name));
        emitter.on("greet", name -> System.out.println("Hi " + name));
        emitter.emit("greet", "Alice");
        emitter.off("greet", id1);
        emitter.emit("greet", "Bob");
    }
}
class EventEmitter {
    private val listeners = HashMap<String, MutableList<Pair<Int, (String) -> Unit>>>()
    private var nextId = 0
    fun on(event: String, cb: (String) -> Unit): Int {
        nextId++
        listeners.getOrPut(event) { mutableListOf() }.add(Pair(nextId, cb))
        return nextId
    }
    fun off(event: String, id: Int) {
        listeners[event]?.removeAll { it.first == id }
    }
    fun emit(event: String, arg: String) {
        listeners[event]?.forEach { it.second(arg) }
    }
}

fun main() {
    val emitter = EventEmitter()
    val id1 = emitter.on("greet") { name -> println("Hello $name") }
    emitter.on("greet") { name -> println("Hi $name") }
    emitter.emit("greet", "Alice")
    emitter.off("greet", id1)
    emitter.emit("greet", "Bob")
}
class EventEmitter {
    var listeners: [String: [(id: Int, cb: (String) -> Void)]] = [:]
    var nextId = 0
    func on(_ event: String, _ cb: @escaping (String) -> Void) -> Int {
        nextId += 1
        listeners[event, default: []].append((id: nextId, cb: cb))
        return nextId
    }
    func off(_ event: String, _ id: Int) {
        listeners[event]?.removeAll { $0.id == id }
    }
    func emit(_ event: String, _ arg: String) {
        for listener in listeners[event] ?? [] {
            listener.cb(arg)
        }
    }
}

let emitter = EventEmitter()
let id1 = emitter.on("greet") { name in print("Hello " + name) }
_ = emitter.on("greet") { name in print("Hi " + name) }
emitter.emit("greet", "Alice")
emitter.off("greet", id1)
emitter.emit("greet", "Bob")
class EventEmitter {
  final Map<String, List<MapEntry<int, void Function(String)>>> listeners = {};
  int nextId = 0;
  int on(String event, void Function(String) cb) {
    nextId++;
    listeners.putIfAbsent(event, () => []).add(MapEntry(nextId, cb));
    return nextId;
  }
  void off(String event, int id) {
    listeners[event]?.removeWhere((l) => l.key == id);
  }
  void emit(String event, String arg) {
    for (final l in listeners[event] ?? []) {
      l.value(arg);
    }
  }
}

void main() {
  final emitter = EventEmitter();
  final id1 = emitter.on('greet', (name) => print('Hello $name'));
  emitter.on('greet', (name) => print('Hi $name'));
  emitter.emit('greet', 'Alice');
  emitter.off('greet', id1);
  emitter.emit('greet', 'Bob');
}
#include <iostream>
#include <functional>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;

class EventEmitter {
    struct Listener {
        int id;
        function<void(const string&)> cb;
    };
    unordered_map<string, vector<Listener>> listeners;
    int nextId = 0;
public:
    int on(const string& event, function<void(const string&)> cb) {
        int id = ++nextId;
        listeners[event].push_back({id, cb});
        return id;
    }
    void off(const string& event, int id) {
        auto& vec = listeners[event];
        for (size_t i = 0; i < vec.size(); i++) {
            if (vec[i].id == id) {
                vec.erase(vec.begin() + i);
                break;
            }
        }
    }
    void emit(const string& event, const string& arg) {
        for (auto& l : listeners[event]) {
            l.cb(arg);
        }
    }
};

int main() {
    EventEmitter emitter;
    int id1 = emitter.on("greet", [](const string& name) { cout << "Hello " << name << endl; });
    emitter.on("greet", [](const string& name) { cout << "Hi " << name << endl; });
    emitter.emit("greet", "Alice");
    emitter.off("greet", id1);
    emitter.emit("greet", "Bob");
    return 0;
}
#include <stdio.h>

typedef void (*Callback)(const char *);

#define MAX 10
int ids[MAX];
Callback callbacks[MAX];
int count = 0;
int nextId = 0;

void hello(const char *name) { printf("Hello %s\n", name); }
void hi(const char *name) { printf("Hi %s\n", name); }

int on(Callback cb) {
    nextId++;
    ids[count] = nextId;
    callbacks[count] = cb;
    count++;
    return nextId;
}

void off(int id) {
    for (int i = 0; i < count; i++) {
        if (ids[i] == id) {
            for (int j = i; j < count - 1; j++) {
                ids[j] = ids[j + 1];
                callbacks[j] = callbacks[j + 1];
            }
            count--;
            break;
        }
    }
}

void emit(const char *arg) {
    for (int i = 0; i < count; i++) {
        callbacks[i](arg);
    }
}

int main() {
    int id1 = on(hello);
    on(hi);
    emit("Alice");
    off(id1);
    emit("Bob");
    return 0;
}