append to items depending on prior item

M

M. Clift

Hi All,

I have tried to come up with a way to do this myself and all I end up with
is very long code.

What I have is a say item1, item4, item2, item1 etc...

What I want to do is append to each item an extra value depending on the
previous item.

from random import *

items = [' item1',' item4',' item2',' item1']

items[0].append choice('1','2','3')
print items

for idx in range(len(items)):
if previous item == ['item1']:
next item.append choice('a','b','c')
if previous item == ['item2']:
next item.append choice('d','e','f')

print items


appended items = item1b, item4a, item2f etc...

Now I know that the code is hopelessly wrong - you can't append a string,
but you get the idea. Doing it using if statements could go on and on. Could
someone show me a short way

Thanks,

M
 
P

Peter Otten

M. Clift said:
Now I know that the code is hopelessly wrong
[...]

Could someone show me a short way
items = "item1 item4 item2 item1".split()
[i + random.choice(dict(item1="abc", item2="def").get(p, [""])) for (p,
i) in zip(items[-1:]+items[:-1], items)]
['item1c', 'item4c', 'item2', 'item1f']


Peter
 
A

Alex Martelli

M. Clift said:
What I have is a say item1, item4, item2, item1 etc...

What I want to do is append to each item an extra value depending on the
previous item.

from random import *

items = [' item1',' item4',' item2',' item1']

items[0].append choice('1','2','3')
print items

for idx in range(len(items)):
if previous item == ['item1']:
next item.append choice('a','b','c')
if previous item == ['item2']:
next item.append choice('d','e','f')

print items

appended items = item1b, item4a, item2f etc...

This latest example totally contrast with everything else you're saying.
How could 'b' get appended to the first 'item1', for example, when
you're trying to use a choice among '1', '2' and '3'?! I'm going to try
to guess what you mean (if you had been a bit more precise in your
example of desired input and output it WOULD have been far better, of
course)...:

def weird_appender(sequence):
choices = dict({None: '123'}, item1='abc', item2='def')
previous = None
for item in sequence:
yield item+random.choice(choices.get(previous, choices[None]))
previous = item

and if for some super=weird reason you want to trample the contents of
list items rather than just operating on a sequence-in / sequence-out
basis, items[:]=weird_appender(items) will serve.


Alex
 
M

M. Clift

Hi Peter,

Thankyou, it looks perfect. At the risk of sounding dumb, however, what do I
print to get your output?

items = "item1 item4 item2 item1".split()
[i + random.choice(dict(item1="abc", item2="def").get(p, [""]))
for (p,i) in zip(items[-1:]+items[:-1], items)]
print ???

Thanks,

M
 
P

Peter Otten

M. Clift said:
Thankyou, it looks perfect. At the risk of sounding dumb, however, what do
I print to get your output?

You would print all the stuff inside [], i. e.

result = [i + random.choice(dict(item1="abc", item2="def").get(p, [""]))
for (p, i) in zip(items[-1:]+items[:-1], items)]
print result

but: the code was *not* meant to be perfect - rather as close as you can get
to obfuscation in Python.
You should first describe exactly what you want in terms of input/output.
Stating a problem precisely is often the hardest and largest part of its
solution. After that try to write a script as _simple_ and _clear_ as you
can (in Python as opposed to your pseudocode).
If you then ask on c.l.py for help with a specific problem you encounter or
for possible improvements, you'll end up with an idiomatic and
understandable solution which is not necessarily the shortest.
In short: short != good.

More practially:
- a plain old for-loop (like in Alex Martelli's post) with a variable to
remember the previous item beats my zip() magic in efficiency and - more
importantly - in clarity.
- if you encounter a long list of if ... elif ... statements, this can often
be simplified into a dictionary lookup.

HTH ...really,
Peter
 
M

M. Clift

Hi Peter,

Any chance you could point me in the direction of that Alex Martelli's post?
Can't seem to find it anywhere.

Thanks,

Malcolm
 
M

M. Clift

Hi,

Strange. I was reading this via wanado news and even now, hours after Alex's
post it hasn't shown up. I only discovered this by re - searching google and
finding the post on dbforums.

Anyway, I've read it now. Thanks Alex. Sorry, I must have been to quick to
post and didn't check what I'd typed. Of course they're all to be appended
using numbers.

M
 
M

M. Clift

Hi All,

First my appologies. I wrote this in my first post;

What I want to do is append to each item an extra value depending on the
previous item.

Too keen to get help, what I should have written is;

What I want to do is append to each item an extra value depending on the
previous item and itself.

Alex gave me this;

def weird_appender(sequence):
choices = dict({None: 'abc'}, item1='abc', item2='def')
previous = None
for item in sequence:
yield item+random.choice(choices.get(previous, choices[None]))
previous = item
print weird_appender(sequence)

What I want to do is append to an item, but rather than just getting this
value based on the previous choice
I'd like to say if previous item is 'item1a' and the current item is item2
append some choice. or else if the current item is
item3 append a diferent choice.

Now, I know none of you are on my payroll (and I have been asking for help a
lot), but if that is easy to impliment I would be grateful
if someone could show me how. However, if it isn't so easy to do, is the
previous code Alex gave me along the right lines for my new requirement?
So that if I go away and change / add to it myself I might eventually get it
to work. If not, could someone point me in the direction I should look
at other than a dictionary method. I see it as a sort of multiplication
lookup table i.e. previous items already appended are looked for along the
x axis, the current item unappended is on the y axis, reading along from
both gives the value to append to the current item.

Thanks for putting up with me,

Malcolm
 
A

Alex Martelli

M. Clift said:
What I want to do is append to each item an extra value depending on the
previous item.

Too keen to get help, what I should have written is;

What I want to do is append to each item an extra value depending on the
previous item and itself.

So, you mean the key is not just the previous, but the pair
(previous,item)? OK, not necessarily a big difference...: you can
either use the pairs as keys, or make a nested dictionary.
Alex gave me this;

def weird_appender(sequence):
choices = dict({None: 'abc'}, item1='abc', item2='def')

Change this to something like:

# what if there IS no 'previous item', i.e., the first time, or for
# all those cases which are not explicititly in the dictionary...:
first_time_choices = {'item1': 'abc', 'item2': 'def', }
# general case
choices = { None: first_time_choices,
'item1': {'item1': 'blu', 'item2': 'ghi', },
'item2': {'item1': 'jkm', 'item2': 'nop', },
}
previous = None
for item in sequence:
yield item+random.choice(choices.get(previous, choices[None]))
previous = item

and here, access the nested dicts -- clearer when done less concisely,
in separate steps rather than all inline:
d = choices.get(previous, first_time_choices)
choose = d.get(item, [''])
yield item + random.choice(choose)
previous = item
print weird_appender(sequence)

this is misaligned -- remove leading space, I don't know how it got
there (it definitely wasn't there in my post!!!). The 'p' of print must
align with the 'd' of 'def weird...'. The print is done after the
function weird_appender is done being defined, most definitely *NOT* as
part of the 'for' loop in said function's body...!!!
What I want to do is append to an item, but rather than just getting this
value based on the previous choice
I'd like to say if previous item is 'item1a' and the current item is item2

Ah, you want to key on the previous _output_ item rather than the
previous _input_ one? OK, then further alter in the latest snippet the
last two statements to be instead:

previous = item + random.choice(choose)
yield previous
append some choice. or else if the current item is
item3 append a diferent choice.

If you LIKE to say if/else if, there's nothing stopping you from saying
it. I think the dictionary accesses are clearer, but changing them into
a few nested if/elif/else trees is hardly difficult - it just (IMHO)
worsens the code's quality, that's all.

Now, I know none of you are on my payroll (and I have been asking for help a
lot), but if that is easy to impliment I would be grateful
if someone could show me how. However, if it isn't so easy to do, is the
previous code Alex gave me along the right lines for my new requirement?

If your requirement is now correctly expressed and divined, yes. If you
gave us the true requirement (what application problem are you actually
trying to solve) rather than asking for advice on how to implement one
design you appear to have already chosen, we might be on a sounder basis
in making such statements, of course.
So that if I go away and change / add to it myself I might eventually get it
to work. If not, could someone point me in the direction I should look
at other than a dictionary method. I see it as a sort of multiplication
lookup table i.e. previous items already appended are looked for along the
x axis, the current item unappended is on the y axis, reading along from
both gives the value to append to the current item.

Right, the nested dictionaries give you something akin to a 2-d array,
except that each axis is indexed by string rather than by number.
Again, this contrasts with your assertion in this very post that you'd
LIKE to say "if" and "else" -- the dictionaries are there exactly in
order to _avoid_ the rich nesting of 'if/elif/else' trees, moving some
complexity from code to "data tables".

Thanks for putting up with me,

No problem, really.


Alex
 
M

M. Clift

Hi Alex,

I'm just gonna say thankyou for your time and effort. I hope that I've left
you and Peter with some hair : )
I can more fully appreciate now that I do not perhaps describe my
requirements as clear as I think that I do. You, however, have managed to
divine my needs, and both you and Peter have highlighted the fact that
perhaps I hadn't thought the problem through well enough in the first place
before I posted.

Anyway, bottom line is that this code will do what I wanted : )

All the best,

Malcolm
 
M

M. Clift

Hi Alex,

How do I print from this?

def weird_appender(sequence):
first_time_choices = {'item1': 'abc', 'item2': 'def', }
choices = { None: first_time_choices,
'item1': {'item1': 'blu', 'item2': 'ghi', },
'item2': {'item1': 'jkm', 'item2': 'nop', }
}

d = choices.get(previous, first_time_choices)
choose = d.get(item, [''])
yield item + random.choice(choose)
previous = item

print ???


Thanks,

Malcolm
 
A

Alex Martelli

M. Clift said:
Hi Alex,

How do I print from this?

def weird_appender(sequence):
first_time_choices = {'item1': 'abc', 'item2': 'def', }
choices = { None: first_time_choices,
'item1': {'item1': 'blu', 'item2': 'ghi', },
'item2': {'item1': 'jkm', 'item2': 'nop', }
}

d = choices.get(previous, first_time_choices)
choose = d.get(item, [''])
yield item + random.choice(choose)
previous = item

print ???

Hmmm, that depends on what (if anything) you _wish_ to print, doesn't
it? print list(weird_appender(whatever_weird_sequence)) is one
possibility, but surely not the only one...


Alex
 
M

M. Clift

Hi Alex,

I can't get this to run. Could you help?

import random

sequence = ['item1','item2','item1']

previous = None

def weird_appender(sequence):
first_time_choices = {'item1': 'abc', 'item2': 'def', }
choices = { None: first_time_choices,
'item1': {'item1': 'blu', 'item2': 'ghi', },
'item2': {'item1': 'jkm', 'item2': 'nop', }
}
previous = None
d = choices.get(previous, first_time_choices)
choose = d.get(item, [''])
previous = item + random.choice(choose)
yield previous

print list(weird_appender(sequence))


# yield item + random.choice(choose)
# previous = item


# previous = item + random.choice(choose)
# yield previous


Thanks,

Malcolm
 
A

Alex Martelli

M. Clift said:
Hi Alex,

I can't get this to run. Could you help?

You seem to have snipped away a 'for item in sequence:' from the
function body...


Alex
 
M

M. Clift

Hi Alex,

A quick reply, thankyou. I'd been experimenting with it to see how it worked
and didn't put it back together right...
It now works perfectly.

All the best,

Malcolm
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,016
Latest member
TatianaCha

Latest Threads

Top