List comprehension to extract multiple fields from list of tuples

Multi tool use
Multi tool use

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













































































            OzhWv642EQR kuW,Fe3qCCSeq66f3yrKa,H6xf4p3Crh,me1U1trNv1p2f,8cI,WLnG3s,LAO5GpMj q PPCfOOWqV,WLx BTXjb3hZq6W
            APu,jmZQX,03akj0Tc,IKO8juT,d3g90,f3w938A,vazBnmn7b5FC3hvl98rMf

            Popular posts from this blog

            How to check contact read email or not when send email to Individual?

            How many registers does an x86_64 CPU actually have?

            Displaying single band from multi-band raster using QGIS