a software engineering interview question I like: computing the median

A software engineering interview question I like: computing the median

我喜欢的一道软件工程面试题:计算中位数

I have a number of questions in my quiver when I’m giving technical interviews to candidates. They are all of a similar flavor. I don’t ask puzzle questions, I find them low value. Instead, I ask questions that are straightforward but have a few angles with which to explore deeper topics. 在进行技术面试时,我的题库里准备了许多问题,它们风格相似。我不喜欢问脑筋急转弯,因为我觉得那没什么价值。相反,我倾向于问一些直截了当、但能从多个角度深入探讨的问题。

Enter the humble median. Write a function that takes an array of numbers and returns the median. At a minimum: this will give you a “Fizz Buzz”-like signal that the candidate can actually program. Reducing an array of values is table stakes. 让我们来看看“中位数”这个简单的问题。编写一个函数,接收一个数字数组并返回其中位数。最起码,这能像“Fizz Buzz”测试一样,让你判断候选人是否具备基本的编程能力。对数组进行归约(Reducing)是面试的入门门槛。

Right out the gate: the numbers must be sorted. Should the function sort them? Should the caller? If the array was passed in by reference is it ok to mutate? How does the API design influence the performance? It has an off-by-one trap. Mind you I don’t care if anyone falls into an off-by-one trap, I fall into them all the time, but you’ll often get a chance to watch someone debug a small problem. 首先要面对的问题是:数字必须是有序的。函数应该负责排序吗?还是由调用者负责?如果数组是通过引用传递的,修改它是否可以?API 设计如何影响性能?这个问题还隐藏着“差一错误”(off-by-one error)的陷阱。请注意,我并不介意候选人是否掉进这个陷阱,我自己也经常犯这种错,但通过这个过程,你通常能观察到候选人调试小问题的能力。

It has a branch: an even length array versus an odd one. It can lead to some discussion about statistics and why you might prefer a median to a mean in most cases. Gives the candidate a chance for some extra points by being so readily testable. Gives the candidate a chance to display some standard library knowledge via statistics. 这个问题包含一个分支逻辑:数组长度为偶数还是奇数。这可以引申出关于统计学的讨论,比如为什么在大多数情况下,你可能更倾向于使用中位数而不是平均数。由于该问题非常容易测试,它也给了候选人加分的机会。同时,它还能让候选人展示对标准库(如 statistics 模块)的了解。

Here’s a Python implementation with discussion comments. 以下是一个带有讨论注释的 Python 实现。

def median(numbers: list[float]) -> float:
    # What should we do if the list is empty?
    # Raise an exception? Return a sentinel value?
    # 如果列表为空,我们该怎么办?
    # 抛出异常?还是返回一个哨兵值?
    if not numbers:
        raise ValueError("median called with empty list")

    # Python is pass-by-reference, what are the
    # implications of sorted() vs numbers.sort()?
    # Python 是引用传递,sorted() 和 numbers.sort() 之间有什么区别?
    numbers = sorted(numbers)
    length = len(numbers)
    mid = length // 2

    # High-quality candidates will bravely import 1,000
    # dependencies to get an is_even library func.
    # 优秀的候选人会勇敢地引入 1000 个依赖项,只为了用一个 is_even 库函数。
    if length % 2 == 0:
        return (numbers[mid - 1] + numbers[mid]) / 2.0
    else:
        return numbers[mid]