List comprehension to extract multiple fields from list of tuples

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
6
down vote

favorite












I have a list of tuples



servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]


I want to create a new list that only has the first two fields as in:



 [('server1', 80), ('server2', 443)]


but I cannot see how to craft a list comprehension for more than one element.



hosts = [x[0] for x in servers] # this works to give me ['server1', server2']

hostswithports = [x[0], x[1] for x in servers] # this does not work


I prefer to learn the pythonic way vs using a loop - what am I doing wrong?










share|improve this question

















  • 2




    hostswithports = [ (x[0], x[1]) for x in servers] does it
    – Patrick Artner
    9 hours ago






  • 3




    loops are pythonic
    – juanpa.arrivillaga
    9 hours ago














up vote
6
down vote

favorite












I have a list of tuples



servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]


I want to create a new list that only has the first two fields as in:



 [('server1', 80), ('server2', 443)]


but I cannot see how to craft a list comprehension for more than one element.



hosts = [x[0] for x in servers] # this works to give me ['server1', server2']

hostswithports = [x[0], x[1] for x in servers] # this does not work


I prefer to learn the pythonic way vs using a loop - what am I doing wrong?










share|improve this question

















  • 2




    hostswithports = [ (x[0], x[1]) for x in servers] does it
    – Patrick Artner
    9 hours ago






  • 3




    loops are pythonic
    – juanpa.arrivillaga
    9 hours ago












up vote
6
down vote

favorite









up vote
6
down vote

favorite











I have a list of tuples



servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]


I want to create a new list that only has the first two fields as in:



 [('server1', 80), ('server2', 443)]


but I cannot see how to craft a list comprehension for more than one element.



hosts = [x[0] for x in servers] # this works to give me ['server1', server2']

hostswithports = [x[0], x[1] for x in servers] # this does not work


I prefer to learn the pythonic way vs using a loop - what am I doing wrong?










share|improve this question













I have a list of tuples



servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]


I want to create a new list that only has the first two fields as in:



 [('server1', 80), ('server2', 443)]


but I cannot see how to craft a list comprehension for more than one element.



hosts = [x[0] for x in servers] # this works to give me ['server1', server2']

hostswithports = [x[0], x[1] for x in servers] # this does not work


I prefer to learn the pythonic way vs using a loop - what am I doing wrong?







python tuples itertools






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 9 hours ago









Bill

6116




6116







  • 2




    hostswithports = [ (x[0], x[1]) for x in servers] does it
    – Patrick Artner
    9 hours ago






  • 3




    loops are pythonic
    – juanpa.arrivillaga
    9 hours ago












  • 2




    hostswithports = [ (x[0], x[1]) for x in servers] does it
    – Patrick Artner
    9 hours ago






  • 3




    loops are pythonic
    – juanpa.arrivillaga
    9 hours ago







2




2




hostswithports = [ (x[0], x[1]) for x in servers] does it
– Patrick Artner
9 hours ago




hostswithports = [ (x[0], x[1]) for x in servers] does it
– Patrick Artner
9 hours ago




3




3




loops are pythonic
– juanpa.arrivillaga
9 hours ago




loops are pythonic
– juanpa.arrivillaga
9 hours ago












4 Answers
4






active

oldest

votes

















up vote
13
down vote



accepted










You can use extended iterable unpacking.



>>> servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]
>>> [(server, port) for server, port, *_ in servers]
>>> [('server1', 80), ('server2', 443)]


Using _ as a throwaway placeholder-name is a common convention.






share|improve this answer


















  • 2




    This is the only one that, by only looking at the line in question, I have any idea what is happening. Readability matters: +1
    – TemporalWolf
    9 hours ago






  • 1




    ... and for older versions, [(server, port) for server, port, _, _ in servers] works just as well.
    – tobias_k
    9 hours ago










  • @tobias_k it is worth noting it handles things differently: a, b, *_ will accept elements with at least two sub-elements. a, b, _, _ only accepts elements with 4 sub-elements. So they are different in how they handle data that doesn't conform to the example. But with conforming data, they are the same... and in Py2.7 you don't get the choice ;)
    – TemporalWolf
    8 hours ago











  • I see I was just missing enclosing parentheses but I really like the readability of this approach
    – Bill
    8 hours ago










  • @TemporalWolf Of course, I thought that was clear, but you are right: OP actually never says anything about the shape of the lists, just that the first two elements are needed, so it might indeed be irregular.
    – tobias_k
    8 hours ago

















up vote
4
down vote













Using basic slicing, which has the benefit of not failing if any of your list elements don't have the expected number of sub-elements.



[el[:2] for el in servers]




[('server1', 80), ('server2', 443)]





share|improve this answer






















  • Suggestion: server_port = slice(2) -> [el[server_port] for ...] would make for nice self-documentation.
    – timgeb
    9 hours ago

















up vote
3
down vote













You could use itemgetter:



from operator import itemgetter


servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]

result = [e for e in map(itemgetter(0, 1), servers)]

print(result)


Output



[('server1', 80), ('server2', 443)]


A more readable alternative is the following:



from operator import itemgetter

get_server_and_port = itemgetter(0, 1)
servers = [('server1', 80, 1, 2), ('server2', 443, 3, 4)]
result = [get_server_and_port(e) for e in servers]

print(result) # [('server1', 80), ('server2', 443)]





share|improve this answer





























    up vote
    2
    down vote













    What you were doing was almost right. You were attempting to translate each tuple in your list into a new tuple. But you forgot to actually declare the tuple. That's what the parentheses are doing:



    hosts = [(x[0], x[1]) for x in servers]





    share|improve this answer




















    • Thanks - I could have sworn I tried that too but obviously I did not!
      – Bill
      8 hours ago










    • @Bill If I had a nickel for every time I did that . . . I'd be able to buy a steak dinner at least
      – Woody1193
      8 hours ago










    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "",
    contentPolicyHtml: "",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53072455%2flist-comprehension-to-extract-multiple-fields-from-list-of-tuples%23new-answer', 'question_page');

    );

    Post as a guest






























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    13
    down vote



    accepted










    You can use extended iterable unpacking.



    >>> servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]
    >>> [(server, port) for server, port, *_ in servers]
    >>> [('server1', 80), ('server2', 443)]


    Using _ as a throwaway placeholder-name is a common convention.






    share|improve this answer


















    • 2




      This is the only one that, by only looking at the line in question, I have any idea what is happening. Readability matters: +1
      – TemporalWolf
      9 hours ago






    • 1




      ... and for older versions, [(server, port) for server, port, _, _ in servers] works just as well.
      – tobias_k
      9 hours ago










    • @tobias_k it is worth noting it handles things differently: a, b, *_ will accept elements with at least two sub-elements. a, b, _, _ only accepts elements with 4 sub-elements. So they are different in how they handle data that doesn't conform to the example. But with conforming data, they are the same... and in Py2.7 you don't get the choice ;)
      – TemporalWolf
      8 hours ago











    • I see I was just missing enclosing parentheses but I really like the readability of this approach
      – Bill
      8 hours ago










    • @TemporalWolf Of course, I thought that was clear, but you are right: OP actually never says anything about the shape of the lists, just that the first two elements are needed, so it might indeed be irregular.
      – tobias_k
      8 hours ago














    up vote
    13
    down vote



    accepted










    You can use extended iterable unpacking.



    >>> servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]
    >>> [(server, port) for server, port, *_ in servers]
    >>> [('server1', 80), ('server2', 443)]


    Using _ as a throwaway placeholder-name is a common convention.






    share|improve this answer


















    • 2




      This is the only one that, by only looking at the line in question, I have any idea what is happening. Readability matters: +1
      – TemporalWolf
      9 hours ago






    • 1




      ... and for older versions, [(server, port) for server, port, _, _ in servers] works just as well.
      – tobias_k
      9 hours ago










    • @tobias_k it is worth noting it handles things differently: a, b, *_ will accept elements with at least two sub-elements. a, b, _, _ only accepts elements with 4 sub-elements. So they are different in how they handle data that doesn't conform to the example. But with conforming data, they are the same... and in Py2.7 you don't get the choice ;)
      – TemporalWolf
      8 hours ago











    • I see I was just missing enclosing parentheses but I really like the readability of this approach
      – Bill
      8 hours ago










    • @TemporalWolf Of course, I thought that was clear, but you are right: OP actually never says anything about the shape of the lists, just that the first two elements are needed, so it might indeed be irregular.
      – tobias_k
      8 hours ago












    up vote
    13
    down vote



    accepted







    up vote
    13
    down vote



    accepted






    You can use extended iterable unpacking.



    >>> servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]
    >>> [(server, port) for server, port, *_ in servers]
    >>> [('server1', 80), ('server2', 443)]


    Using _ as a throwaway placeholder-name is a common convention.






    share|improve this answer














    You can use extended iterable unpacking.



    >>> servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]
    >>> [(server, port) for server, port, *_ in servers]
    >>> [('server1', 80), ('server2', 443)]


    Using _ as a throwaway placeholder-name is a common convention.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 9 hours ago

























    answered 9 hours ago









    timgeb

    40.6k105580




    40.6k105580







    • 2




      This is the only one that, by only looking at the line in question, I have any idea what is happening. Readability matters: +1
      – TemporalWolf
      9 hours ago






    • 1




      ... and for older versions, [(server, port) for server, port, _, _ in servers] works just as well.
      – tobias_k
      9 hours ago










    • @tobias_k it is worth noting it handles things differently: a, b, *_ will accept elements with at least two sub-elements. a, b, _, _ only accepts elements with 4 sub-elements. So they are different in how they handle data that doesn't conform to the example. But with conforming data, they are the same... and in Py2.7 you don't get the choice ;)
      – TemporalWolf
      8 hours ago











    • I see I was just missing enclosing parentheses but I really like the readability of this approach
      – Bill
      8 hours ago










    • @TemporalWolf Of course, I thought that was clear, but you are right: OP actually never says anything about the shape of the lists, just that the first two elements are needed, so it might indeed be irregular.
      – tobias_k
      8 hours ago












    • 2




      This is the only one that, by only looking at the line in question, I have any idea what is happening. Readability matters: +1
      – TemporalWolf
      9 hours ago






    • 1




      ... and for older versions, [(server, port) for server, port, _, _ in servers] works just as well.
      – tobias_k
      9 hours ago










    • @tobias_k it is worth noting it handles things differently: a, b, *_ will accept elements with at least two sub-elements. a, b, _, _ only accepts elements with 4 sub-elements. So they are different in how they handle data that doesn't conform to the example. But with conforming data, they are the same... and in Py2.7 you don't get the choice ;)
      – TemporalWolf
      8 hours ago











    • I see I was just missing enclosing parentheses but I really like the readability of this approach
      – Bill
      8 hours ago










    • @TemporalWolf Of course, I thought that was clear, but you are right: OP actually never says anything about the shape of the lists, just that the first two elements are needed, so it might indeed be irregular.
      – tobias_k
      8 hours ago







    2




    2




    This is the only one that, by only looking at the line in question, I have any idea what is happening. Readability matters: +1
    – TemporalWolf
    9 hours ago




    This is the only one that, by only looking at the line in question, I have any idea what is happening. Readability matters: +1
    – TemporalWolf
    9 hours ago




    1




    1




    ... and for older versions, [(server, port) for server, port, _, _ in servers] works just as well.
    – tobias_k
    9 hours ago




    ... and for older versions, [(server, port) for server, port, _, _ in servers] works just as well.
    – tobias_k
    9 hours ago












    @tobias_k it is worth noting it handles things differently: a, b, *_ will accept elements with at least two sub-elements. a, b, _, _ only accepts elements with 4 sub-elements. So they are different in how they handle data that doesn't conform to the example. But with conforming data, they are the same... and in Py2.7 you don't get the choice ;)
    – TemporalWolf
    8 hours ago





    @tobias_k it is worth noting it handles things differently: a, b, *_ will accept elements with at least two sub-elements. a, b, _, _ only accepts elements with 4 sub-elements. So they are different in how they handle data that doesn't conform to the example. But with conforming data, they are the same... and in Py2.7 you don't get the choice ;)
    – TemporalWolf
    8 hours ago













    I see I was just missing enclosing parentheses but I really like the readability of this approach
    – Bill
    8 hours ago




    I see I was just missing enclosing parentheses but I really like the readability of this approach
    – Bill
    8 hours ago












    @TemporalWolf Of course, I thought that was clear, but you are right: OP actually never says anything about the shape of the lists, just that the first two elements are needed, so it might indeed be irregular.
    – tobias_k
    8 hours ago




    @TemporalWolf Of course, I thought that was clear, but you are right: OP actually never says anything about the shape of the lists, just that the first two elements are needed, so it might indeed be irregular.
    – tobias_k
    8 hours ago












    up vote
    4
    down vote













    Using basic slicing, which has the benefit of not failing if any of your list elements don't have the expected number of sub-elements.



    [el[:2] for el in servers]




    [('server1', 80), ('server2', 443)]





    share|improve this answer






















    • Suggestion: server_port = slice(2) -> [el[server_port] for ...] would make for nice self-documentation.
      – timgeb
      9 hours ago














    up vote
    4
    down vote













    Using basic slicing, which has the benefit of not failing if any of your list elements don't have the expected number of sub-elements.



    [el[:2] for el in servers]




    [('server1', 80), ('server2', 443)]





    share|improve this answer






















    • Suggestion: server_port = slice(2) -> [el[server_port] for ...] would make for nice self-documentation.
      – timgeb
      9 hours ago












    up vote
    4
    down vote










    up vote
    4
    down vote









    Using basic slicing, which has the benefit of not failing if any of your list elements don't have the expected number of sub-elements.



    [el[:2] for el in servers]




    [('server1', 80), ('server2', 443)]





    share|improve this answer














    Using basic slicing, which has the benefit of not failing if any of your list elements don't have the expected number of sub-elements.



    [el[:2] for el in servers]




    [('server1', 80), ('server2', 443)]






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 9 hours ago

























    answered 9 hours ago









    user3483203

    27.7k72350




    27.7k72350











    • Suggestion: server_port = slice(2) -> [el[server_port] for ...] would make for nice self-documentation.
      – timgeb
      9 hours ago
















    • Suggestion: server_port = slice(2) -> [el[server_port] for ...] would make for nice self-documentation.
      – timgeb
      9 hours ago















    Suggestion: server_port = slice(2) -> [el[server_port] for ...] would make for nice self-documentation.
    – timgeb
    9 hours ago




    Suggestion: server_port = slice(2) -> [el[server_port] for ...] would make for nice self-documentation.
    – timgeb
    9 hours ago










    up vote
    3
    down vote













    You could use itemgetter:



    from operator import itemgetter


    servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]

    result = [e for e in map(itemgetter(0, 1), servers)]

    print(result)


    Output



    [('server1', 80), ('server2', 443)]


    A more readable alternative is the following:



    from operator import itemgetter

    get_server_and_port = itemgetter(0, 1)
    servers = [('server1', 80, 1, 2), ('server2', 443, 3, 4)]
    result = [get_server_and_port(e) for e in servers]

    print(result) # [('server1', 80), ('server2', 443)]





    share|improve this answer


























      up vote
      3
      down vote













      You could use itemgetter:



      from operator import itemgetter


      servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]

      result = [e for e in map(itemgetter(0, 1), servers)]

      print(result)


      Output



      [('server1', 80), ('server2', 443)]


      A more readable alternative is the following:



      from operator import itemgetter

      get_server_and_port = itemgetter(0, 1)
      servers = [('server1', 80, 1, 2), ('server2', 443, 3, 4)]
      result = [get_server_and_port(e) for e in servers]

      print(result) # [('server1', 80), ('server2', 443)]





      share|improve this answer
























        up vote
        3
        down vote










        up vote
        3
        down vote









        You could use itemgetter:



        from operator import itemgetter


        servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]

        result = [e for e in map(itemgetter(0, 1), servers)]

        print(result)


        Output



        [('server1', 80), ('server2', 443)]


        A more readable alternative is the following:



        from operator import itemgetter

        get_server_and_port = itemgetter(0, 1)
        servers = [('server1', 80, 1, 2), ('server2', 443, 3, 4)]
        result = [get_server_and_port(e) for e in servers]

        print(result) # [('server1', 80), ('server2', 443)]





        share|improve this answer














        You could use itemgetter:



        from operator import itemgetter


        servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]

        result = [e for e in map(itemgetter(0, 1), servers)]

        print(result)


        Output



        [('server1', 80), ('server2', 443)]


        A more readable alternative is the following:



        from operator import itemgetter

        get_server_and_port = itemgetter(0, 1)
        servers = [('server1', 80, 1, 2), ('server2', 443, 3, 4)]
        result = [get_server_and_port(e) for e in servers]

        print(result) # [('server1', 80), ('server2', 443)]






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 9 hours ago

























        answered 9 hours ago









        Daniel Mesejo

        5,338620




        5,338620




















            up vote
            2
            down vote













            What you were doing was almost right. You were attempting to translate each tuple in your list into a new tuple. But you forgot to actually declare the tuple. That's what the parentheses are doing:



            hosts = [(x[0], x[1]) for x in servers]





            share|improve this answer




















            • Thanks - I could have sworn I tried that too but obviously I did not!
              – Bill
              8 hours ago










            • @Bill If I had a nickel for every time I did that . . . I'd be able to buy a steak dinner at least
              – Woody1193
              8 hours ago














            up vote
            2
            down vote













            What you were doing was almost right. You were attempting to translate each tuple in your list into a new tuple. But you forgot to actually declare the tuple. That's what the parentheses are doing:



            hosts = [(x[0], x[1]) for x in servers]





            share|improve this answer




















            • Thanks - I could have sworn I tried that too but obviously I did not!
              – Bill
              8 hours ago










            • @Bill If I had a nickel for every time I did that . . . I'd be able to buy a steak dinner at least
              – Woody1193
              8 hours ago












            up vote
            2
            down vote










            up vote
            2
            down vote









            What you were doing was almost right. You were attempting to translate each tuple in your list into a new tuple. But you forgot to actually declare the tuple. That's what the parentheses are doing:



            hosts = [(x[0], x[1]) for x in servers]





            share|improve this answer












            What you were doing was almost right. You were attempting to translate each tuple in your list into a new tuple. But you forgot to actually declare the tuple. That's what the parentheses are doing:



            hosts = [(x[0], x[1]) for x in servers]






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 9 hours ago









            Woody1193

            1,497725




            1,497725











            • Thanks - I could have sworn I tried that too but obviously I did not!
              – Bill
              8 hours ago










            • @Bill If I had a nickel for every time I did that . . . I'd be able to buy a steak dinner at least
              – Woody1193
              8 hours ago
















            • Thanks - I could have sworn I tried that too but obviously I did not!
              – Bill
              8 hours ago










            • @Bill If I had a nickel for every time I did that . . . I'd be able to buy a steak dinner at least
              – Woody1193
              8 hours ago















            Thanks - I could have sworn I tried that too but obviously I did not!
            – Bill
            8 hours ago




            Thanks - I could have sworn I tried that too but obviously I did not!
            – Bill
            8 hours ago












            @Bill If I had a nickel for every time I did that . . . I'd be able to buy a steak dinner at least
            – Woody1193
            8 hours ago




            @Bill If I had a nickel for every time I did that . . . I'd be able to buy a steak dinner at least
            – Woody1193
            8 hours ago

















             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53072455%2flist-comprehension-to-extract-multiple-fields-from-list-of-tuples%23new-answer', 'question_page');

            );

            Post as a guest













































































            Comments

            Popular posts from this blog

            Long meetings (6-7 hours a day): Being “babysat” by supervisor

            Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

            Confectionery