public static function filter($collection, Expression $expr)
    {
        if (is_array($collection)) {
            return array_filter($collection, array($expr, 'evaluate'));
        }

        if (!($collection instanceof Traversable && $collection instanceof ArrayAccess)) {
            throw new InvalidArgumentException(sprintf(
                'Expected an array or an instance of Traversable and ArrayAccess. Got: %s',
                is_object($collection) ? get_class($collection) : gettype($collection)
            ));
        }

        $clone = clone $collection;

        foreach ($collection as $key => $value) {
            if (!$expr->evaluate($value)) {
                unset($clone[$key]);
            }
        }

        return $clone;
    }