4

Question

Is there a way to do something like

some_list = [int(x) for x in input().split()]

but return a collections.deque object instead of a list?  In particular, I'm attempting to avoid creating a list and converting it with deque(some_list) since that adds a factor of O(n) to the time complexity as demonstrated here and explained here.

Context

I'm working on a practice HackerRank problem for fun (but will avoid sharing it here to avoid the risk of people spoiling the fun of finding an answer).  Consequently, I won't be giving an example output since it would only make sense within the full context of the problem.  There are, however, some relevant things I can disclose that don't run the risk of spoilers.

Relevant stuff

  1. I'm taking in very large lists/deques (up to 100k elements) via stdin.  They need to be converted to integers after (or while) being read in.

  2. Elements in the list/deque itself are between 1 and 231.

  3. I need to quickly compare and pop from both ends.  There's no need to (a) look in the middle of the data, nor (b) sort it.

  4. I'm restricted to using stdin to take in the data, but I will know the size of the list/deque ahead of time. 

  5. Fast runtime execution is desired, but I'm unfortunately restricted from using Numpy, Pandas, and Numba to help.

My reasoning for thinking about deques and list comprehensions

Because of (3) & (5), it seems like the deque object is the best way to go.  Because of (1) & (5), I'd like to convert the input into integers right away which is why list comprehensions came to mind. 

Example input

The 1st line, n, tells me how many integers will be on the 2nd line.

4
5 2 42 199
Example code snippet to read in input

The following code works for reading in the input while converting it to integers:

n = int(input())
wish_this_was_a_deque = [int(x) for x in input().split()]

But as mentioned before, I'd like to immediately convert the input into integers while also creating a deque and skipping the list entirely (for performance speed reasons). 

Concluding remarks

Perhaps I'm mistaken in thinking that immediately converting the string input from stdin into integers and storing them in a deque would be faster doing this:

from collections import deque
# Get input, split on spaces, covert to integers, append to some_big_list
some_big_list = [int(x) for x in input().split()]
# Convert some_big_list into a deque
some_big_deque = deque(some_big_list)

If so, please feel free to correct this misconception even if there is a way to do a "deque comprehension". 

In any case, I'm still interested if a "deque comprehension" is possible.

1 Answers1

3

Python offers a few types of comprehensions, but the most general form is the generator comprehension. When you write

[int(x) for x in input().split()]

This produces a list immediately. But without brackets

int(x) for x in input().split()

this is a generator comprehension. It produces a lazy iterable that, when evaluated, will produce the values. It's as though we had written

def my_generator():
  for x in input().split():
    yield int(x)

my_generator()

but much, much shorter. Now, the reason this is useful is that deque, like many built-in Python collections, takes an arbitrary iterable as its constructor argument. And a generator is a type of iterable. So to get rid of the intermediate list, take your list comprehension

some_big_deque = deque([int(x) for x in input().split()])

and remove the brackets

some_big_deque = deque(int(x) for x in input().split()) # Look, Ma, no brackets!
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116