add elements to indexed list locations

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • leventyilmaz@gmail.com

    #1

    add elements to indexed list locations

    Hi,

    I have a very simple problem, but do not know an elegant way to
    accomplish this.
    ###
    # I have a list of names:
    names = ['clark', 'super', 'peter', 'spider', 'bruce', 'bat']

    # and another set of names that I want to insert into
    # the names list at some indexed locations:
    surnames = { 1: 'kent', 3:'parker', 5:'wayne' }

    # The thing I couldn't figure out is, after I insert a
    # surname the rest of the indices are not valid.
    # That is, the following won't work:
    for i, x in surnames.iterit ems():
    names.insert(i, surnames[i])
    ###

    I am searching a nice way to do this. For instance, is there a more
    robust way to store indices (as some sort of pointers maybe?)

    - Levent

  • Diez B. Roggisch

    #2
    Re: add elements to indexed list locations

    leventyilmaz@gm ail.com schrieb:[color=blue]
    > Hi,
    >
    > I have a very simple problem, but do not know an elegant way to
    > accomplish this.
    > ###
    > # I have a list of names:
    > names = ['clark', 'super', 'peter', 'spider', 'bruce', 'bat']
    >
    > # and another set of names that I want to insert into
    > # the names list at some indexed locations:
    > surnames = { 1: 'kent', 3:'parker', 5:'wayne' }
    >
    > # The thing I couldn't figure out is, after I insert a
    > # surname the rest of the indices are not valid.
    > # That is, the following won't work:
    > for i, x in surnames.iterit ems():
    > names.insert(i, surnames[i])
    > ###
    >
    > I am searching a nice way to do this. For instance, is there a more
    > robust way to store indices (as some sort of pointers maybe?)[/color]

    Use a dictionary for both of them?

    The concept of indices is that they IMPLY a position. So either you work
    in a way that you e.g. add the surnames in a defined order and adjust
    the subsequent indices, or you discard the approach entirely and e.g use
    a map of first to surnames.

    Diez

    Comment

    • Alexis Roda

      #3
      Re: add elements to indexed list locations

      En/na leventyilmaz@gm ail.com ha escrit:[color=blue]
      > Hi,
      >
      > I have a very simple problem, but do not know an elegant way to
      > accomplish this.
      > ###
      > # I have a list of names:
      > names = ['clark', 'super', 'peter', 'spider', 'bruce', 'bat']
      >
      > # and another set of names that I want to insert into
      > # the names list at some indexed locations:
      > surnames = { 1: 'kent', 3:'parker', 5:'wayne' }
      >
      > # The thing I couldn't figure out is, after I insert a
      > # surname the rest of the indices are not valid.
      > # That is, the following won't work:
      > for i, x in surnames.iterit ems():
      > names.insert(i, surnames[i])
      > ###[/color]

      In my previous post I've misunderstood the problem. Here is a valid
      solution:

      keys = surnames.keys()
      keys.sort()
      count = 0
      for i in keys :
      names.insert(i + count, surnames[i])
      count = count + 1


      HTH

      Comment

      • Steven Bethard

        #4
        Re: add elements to indexed list locations

        leventyilmaz@gm ail.com wrote:[color=blue]
        > # I have a list of names:
        > names = ['clark', 'super', 'peter', 'spider', 'bruce', 'bat']
        >
        > # and another set of names that I want to insert into
        > # the names list at some indexed locations:
        > surnames = { 1: 'kent', 3:'parker', 5:'wayne' }
        >
        > # The thing I couldn't figure out is, after I insert a
        > # surname the rest of the indices are not valid.
        > # That is, the following won't work:
        > for i, x in surnames.iterit ems():
        > names.insert(i, surnames[i])[/color]

        This seems to work (tested only with what you see below)::
        [color=blue][color=green][color=darkred]
        >>> names = ['clark', 'super', 'peter', 'spider', 'bruce', 'bat']
        >>> surnames = {1:'kent', 3:'parker', 5:'wayne'}
        >>> for index in sorted(surnames , reverse=True):[/color][/color][/color]
        ... names.insert(in dex, surnames[index])
        ...[color=blue][color=green][color=darkred]
        >>> names[/color][/color][/color]
        ['clark', 'kent', 'super', 'peter', 'parker', 'spider', 'bruce',
        'wayne', 'bat']

        I just did the inserts from right to left, that is, starting at the end.
        That way, after an insert, I don't have to adjust any indices.

        You may also find that if you do a lot of inserts into the list, it may
        be more efficient to create a new list, e.g.::
        [color=blue][color=green][color=darkred]
        >>> names = ['clark', 'super', 'peter', 'spider', 'bruce', 'bat']
        >>> surnames = {1:'kent', 3:'parker', 5:'wayne'}
        >>> new_names = []
        >>> for i, name in enumerate(names ):[/color][/color][/color]
        ... if i in surnames:
        ... new_names.appen d(surnames[i])
        ... new_names.appen d(name)
        ...[color=blue][color=green][color=darkred]
        >>> new_names[/color][/color][/color]
        ['clark', 'kent', 'super', 'peter', 'parker', 'spider', 'bruce',
        'wayne', 'bat']


        STeVe

        Comment

        • levent

          #5
          Re: add elements to indexed list locations

          Thanks for the answers. Enumerating in reverse is indeed quite a smart
          idea.

          The fact is though, I overly simplified the task in the super-hero
          example. In the real case, the dictionary keys are not necessarily the
          indices for inserts; that is to say, the inserts do not necessarily
          take place in some sorted order.

          I think I was thinking more of a linked-list idea, where you do not
          store the indices as integers to some random access array but rather as
          pointers into list's nodes. Then the subsequent inserts would not hurt
          previously stored pointers. For those who know a bit C++/STL here is a
          sketch of the idea:

          name_list heros;
          heros.push_back ("clark");
          // ... add the rest
          indexed_name_li st surnames;
          surnames.push_b ack(
          make_pair( find( heros.begin(), heros.end(), "clark"), "kent") )
          ); // the find function returns an iterator to appropriate location
          // ... add the rest

          for_each(surnam es.begin(), surnames.end(), insert_surnames )
          // insert_surnames is a callback that receives a single indexed surname
          // at a time and does the job, without affecting outer iterators.


          I was wondering how to make indices as *robust* in Python... Any ideas?


          PS: following is the compilable code-let of the task in C++

          // =============== =============== =============== =======
          #include <iostream>
          #include <list>
          #include <vector>
          #include <map>
          #include <string>
          #include <algorithm>

          using namespace std;
          typedef string name;
          typedef pair<list<name> ::iterator, string> indexed_name;

          void insert_name( list<name>* into, indexed_name in ) {
          into->insert(in.firs t, in.second);
          }

          int main() {
          using namespace std;
          // Define super-heros (fathers ignored)
          list<name> heros;
          heros.push_back ("super");
          heros.push_back ("clark");
          heros.push_back ("spider");
          heros.push_back ("peter");
          heros.push_back ("bat");
          heros.push_back ("bruce");

          // Assign father names to proper son
          list<indexed_na me> surnames;
          surnames.push_b ack( // ++ is to have surname inserted _after_ the
          name
          make_pair(++fin d(heros.begin() ,heros.end(),"c lark"),
          string("kent"))
          );
          surnames.push_b ack(
          make_pair(++fin d(heros.begin() ,heros.end(),"p eter"),
          string("parker" ))
          );
          surnames.push_b ack(
          make_pair(++fin d(heros.begin() ,heros.end(),"b ruce"),
          string("wayne") )
          );

          // Insert surnames succeeding appropriate heros
          for_each(surnam es.begin(), surnames.end(),
          bind1st(ptr_fun (insert_name), &heros) );

          // Salute the heros
          copy(heros.begi n(),heros.end() ,ostream_iterat or<string>(cout ," "));
          cout << endl;
          return 0;
          }

          // =============== =============== =============== ========

          Comment

          • Peter Otten

            #6
            Re: add elements to indexed list locations

            levent wrote:
            [color=blue]
            > Thanks for the answers. Enumerating in reverse is indeed quite a smart
            > idea.
            >
            > The fact is though, I overly simplified the task in the super-hero
            > example. In the real case, the dictionary keys are not necessarily the
            > indices for inserts; that is to say, the inserts do not necessarily
            > take place in some sorted order.
            >
            > I think I was thinking more of a linked-list idea, where you do not
            > store the indices as integers to some random access array but rather as
            > pointers into list's nodes. Then the subsequent inserts would not hurt
            > previously stored pointers. For those who know a bit C++/STL here is a
            > sketch of the idea:
            >
            > name_list heros;
            > heros.push_back ("clark");
            > // ... add the rest
            > indexed_name_li st surnames;
            > surnames.push_b ack(
            > make_pair( find( heros.begin(), heros.end(), "clark"), "kent") )
            > ); // the find function returns an iterator to appropriate location
            > // ... add the rest
            >
            > for_each(surnam es.begin(), surnames.end(), insert_surnames )
            > // insert_surnames is a callback that receives a single indexed surname
            > // at a time and does the job, without affecting outer iterators.
            >
            >
            > I was wondering how to make indices as *robust* in Python... Any ideas?[/color]

            Python's list is technically a vector. You can therefore either search for
            the insertion point in a timely fashion:

            heros = ["super", "clark", "spider", "peter", "bat", "bruce"]
            names = [("clark", "kent"), ("peter", "parker"), ("bruce", "wayne")]

            for first, last in names:
            heros.insert(he ros.index(first )+1, last)
            print heros

            or you have to snatch a real (linked) list from somewhere. Here's an ad-hoc
            implementation:

            class Node(object):
            def __init__(self, value, next=None):
            self.value = value
            self.right = next
            def __str__(self):
            return "List(%s)" % ", ".join(repr(n.v alue) for n in self)
            def __iter__(self):
            item = self
            while item:
            yield item
            item = item.right
            def find(self, value):
            for item in self:
            if item.value == value:
            return item
            raise ValueError("%r not found" % (value,))
            def insert_after(se lf, value):
            self.right = Node(value, self.right)
            @staticmethod
            def from_list(items ):
            items = iter(items)
            try:
            first = items.next()
            except StopIteration:
            raise ValueError("emp ty lists not supported")
            cur = head = Node(first)
            for value in items:
            node = Node(value)
            cur.right = node
            cur = node
            return head

            if __name__ == "__main__":
            heros = ["super", "clark", "spider", "peter", "bat", "bruce"]
            heros = Node.from_list( heros)
            names = [("clark", "kent"), ("peter", "parker"), ("bruce", "wayne")]
            surnames = [(heros.find(f), s) for f, s in names]
            print heros
            for node, value in surnames:
            node.insert_aft er(value)
            print heros

            Peter

            Comment

            • Marc 'BlackJack' Rintsch

              #7
              Re: add elements to indexed list locations

              In <1150528979.036 821.246410@g10g 2000cwb.googleg roups.com>, levent wrote:
              [color=blue]
              > I think I was thinking more of a linked-list idea, where you do not
              > store the indices as integers to some random access array but rather as
              > pointers into list's nodes. Then the subsequent inserts would not hurt
              > previously stored pointers. For those who know a bit C++/STL here is a
              > sketch of the idea:
              >
              > name_list heros;
              > heros.push_back ("clark");
              > // ... add the rest
              > indexed_name_li st surnames;
              > surnames.push_b ack(
              > make_pair( find( heros.begin(), heros.end(), "clark"), "kent") )
              > ); // the find function returns an iterator to appropriate location
              > // ... add the rest
              >
              > for_each(surnam es.begin(), surnames.end(), insert_surnames )
              > // insert_surnames is a callback that receives a single indexed surname
              > // at a time and does the job, without affecting outer iterators.
              >
              >
              > I was wondering how to make indices as *robust* in Python... Any ideas?[/color]

              What about putting all information for each super hero into an object or
              at least a list? And those objects/lists can then be stored into a
              dictionary with the first name of the heroes as key. Something like this:

              heroes = [['super', 'clark'], ['spider', 'peter'], ['bat', 'bruce']]

              name2hero = dict((hero[1], hero) for hero in heroes)

              fullnames = [['clark', 'kent'], ['peter', 'parker'], ['bruce', 'wayne']]
              for name, surname in fullnames:
              name2hero[name].append(surname )

              for hero in heroes:
              print 'Hello %s a.k.a %s %s' % tuple(hero)

              IMHO you shouldn't try to program C++ in Python. Take a step back and
              describe *what* you want to achieve and not *how* you do it in another
              language. And then implement it in Python.

              Ciao,
              Marc 'BlackJack' Rintsch

              Comment

              • Steven Bethard

                #8
                Re: add elements to indexed list locations

                levent wrote:[color=blue]
                > Thanks for the answers. Enumerating in reverse is indeed quite a smart
                > idea.
                >
                > The fact is though, I overly simplified the task in the super-hero
                > example. In the real case, the dictionary keys are not necessarily the
                > indices for inserts; that is to say, the inserts do not necessarily
                > take place in some sorted order.
                >
                > I think I was thinking more of a linked-list idea, where you do not
                > store the indices as integers to some random access array but rather as
                > pointers into list's nodes. Then the subsequent inserts would not hurt
                > previously stored pointers. For those who know a bit C++/STL here is a
                > sketch of the idea:[/color]

                Sorry, I don't know C++/STL, so I don't understand the example you gave.
                If your dict doesn't already come with the indices, can't you just
                create a dict that does?
                [color=blue][color=green][color=darkred]
                >>> heros = ["super", "clark", "spider", "peter", "bat", "bruce"]
                >>> names = dict(clark="ken t", peter="parker", bruce="wayne")
                >>> heros_indices = {}
                >>> for index, hero_word in enumerate(heros ):[/color][/color][/color]
                .... if hero_word in names:
                .... heros_indices[index + 1] = names[hero_word]
                ....[color=blue][color=green][color=darkred]
                >>> for index in sorted(heros_in dices, reverse=True):[/color][/color][/color]
                .... heros.insert(in dex, heros_indices[index])
                ....[color=blue][color=green][color=darkred]
                >>> heros[/color][/color][/color]
                ['super', 'clark', 'kent', 'spider', 'peter', 'parker', 'bat', 'bruce',
                'wayne']

                STeVe

                Comment

                Working...