473,386 Members | 1,785 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Help with a reverse dictionary lookup

Hi all,

I have a dict which looks like this..

dict={'130nm': {'umc': ['1p6m_1.2-3.3_fsg_ms']},
'180nm': {'chartered': ['2p6m_1.8-3.3_sal_ms'], 'tsmc':
['1p6m_1.8-3.3_sal_log', '1p6m_1.8-3.3_sal_ms']},
'250nm': {'umc': ['2p6m_1.8-3.3_sal_ms'], 'tsmc':
['1p6m_2.2-3.5_sal_log', '1p6m_1.8-3.3_sal_ms']}
}

For clarification:
130nm,180nm,250nm refer to Nodes
tsmc,chartered,umc refer to Foundries
1p6m..blah, 2p6m..blah refer to Process

I want a function which can do this:

nodes = getNodes()
should return a list [130nm,180nm,250nm]

nodes = getNodes(Foundry="umc")
should return a list [130nm,250nm]

nodes = getNodes(Process="2p6m_1.8-3.3_sal_ms")
should return a list [180nm,250nm]

nodes = getNodes(Foundry="umc", Process="2p6m_1.8-3.3_sal_ms")
should return a list [250nm]

nodes = getNodes(Foundry="foo", Process="2p6m_1.8-3.3_sal_ms")
should return None

Obviously I want to extend this to Each area ( i.e., getFoundry(),
getProcess() ) but I can do that. I just don't know how to easily do
this reverse kind of look up? Can someone help me on this?

Mar 10 '06 #1
8 7024
On Thu, 2006-03-09 at 15:51 -0800, rh0dium wrote:
Hi all,

I have a dict which looks like this..

dict={'130nm': {'umc': ['1p6m_1.2-3.3_fsg_ms']},
'180nm': {'chartered': ['2p6m_1.8-3.3_sal_ms'], 'tsmc':
['1p6m_1.8-3.3_sal_log', '1p6m_1.8-3.3_sal_ms']},
'250nm': {'umc': ['2p6m_1.8-3.3_sal_ms'], 'tsmc':
['1p6m_2.2-3.5_sal_log', '1p6m_1.8-3.3_sal_ms']}
}

For clarification:
130nm,180nm,250nm refer to Nodes
tsmc,chartered,umc refer to Foundries
1p6m..blah, 2p6m..blah refer to Process

I want a function which can do this:

nodes = getNodes()
should return a list [130nm,180nm,250nm]
I'm not going to write your function for you but the following should
help you get started.

dict.keys() <-- returns a list of the keys in your dictionary

[130nm,180nm,250nm]

nodes = getNodes(Foundry="umc")
should return a list [130nm,250nm]

Here you want to check if the key in the child dictionary matches some
text:

Eg:

Foundry = 'umc'
FoundryList = []
for key in dict.keys:
val = dict.get(key)
if Foundry in val.keys():
FoundryList.append(key)

print FoundryList

[130nm,250nm]
nodes = getNodes(Process="2p6m_1.8-3.3_sal_ms")
should return a list [180nm,250nm]

Same concept here:

Process = ['2p6m_1.8-3.3_sal_ms']
ProcessList = []
for key in dict.keys():
val = dict.get(key)
if Process in val.values():
ProcessList.append(key)

print ProcessList

[180nm,250nm]
So key concepts you need are:

- Get a list of keys from the dictionary <-- dict.keys()
- Get the value matching a key <-- dict.get(key)
- Get a list of values from the dictionary <-- dict.values()

This should be enough to get you going.
nodes = getNodes(Foundry="umc", Process="2p6m_1.8-3.3_sal_ms")
should return a list [250nm]

nodes = getNodes(Foundry="foo", Process="2p6m_1.8-3.3_sal_ms")
should return None

Obviously I want to extend this to Each area ( i.e., getFoundry(),
getProcess() ) but I can do that. I just don't know how to easily do
this reverse kind of look up? Can someone help me on this?

--
http://mail.python.org/mailman/listinfo/python-list

--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.

Mar 10 '06 #2
Here's the illegible gibberish version of your function. Once you
understand completely the following line of code, you will be well on
your way to Python nirvana:

getNodes = lambda Foundry=None,Process=None: [node for node,foundries
in dict.iteritems() if ((Foundry is None) and ((Process is None) or
(len([foundry for foundry,processes in foundries.iteritems() if Process
in processes]) > 0))) or ((Foundry in foundries) and ((Process is None)
or (Process in foundries[Foundry])))]

# ex:
getNodes(Foundry="umc", Process="2p6m_1.8-3.3_sal_ms")

# note: returns an empty list rather than None if no matching nodes
exist
# hint: You'll probably want to do rearrange your data structure or do
some caching if you have a large dataset. The dict-and-list solution
doesn't make this search very efficient.

And: I just noticed that len() won't work with a generator expression
as its argument. What's up with that?

Mar 10 '06 #3
Thanks!!

I got all of this. The problem that I was trying to figure out was
this.

Basically there are multiple combinatories here - I was hoping someone
could point me to a general approach. Writing the actual funtion is
not necessary - as you pointed out I can certainly do that. Here is my
problem - I did exactly as you and said OK I can

if Foundry==None and Process==None:

elif Foundy==None and Process!=None:

elif Foundy!=None and Process==None:

elif Foundy!=None and Process!=None:

But this seems very ugly... And if I want to do this for the three
areas, it seems very repetitive. I was looking for a better way to
break this down which is reusable.

Thanks for the help - I guess I should have been more clear.

Mar 10 '06 #4
Hey thanks - OK how would you arrange the data structure? I think that
is my problem - I can arrange in any order - I just want something
which makes sense - this "seemed" logical but can you point me in a
better method.. Basically I am parsing a directory structure:

TECHROOT/
130nm/
tsmc/
1p2m<blah>
2p2m<blah>
umc/
3p2m<blah>
180nm/
tsmc/
1p2m<blah>

Any thoughts -- To parse this I use this..
def _getNodes(self):
self.nodes={}
for node in os.listdir(self.foundrypath):
node = os.path.join( self.foundrypath, node)
if os.path.isdir(node):
self.logger.debug("Node found - %s" % node)
self.nodes[os.path.basename(node)]={}
else:
self.logger.debug("Excluding %s" % node)

return self.nodes

def _getFoundries(self):
for node in self.nodes:
node = os.path.join( self.foundrypath, node)
for foundry in os.listdir(node):
foundry = os.path.join( node, foundry)
if os.path.isdir(foundry):
self.logger.debug("Foundry found - %s" % foundry)
if os.path.basename(foundry) != "smsc":

self.nodes[os.path.basename(node)][os.path.basename(foundry)]=[]
else:
self.logger.debug("smsc foundry found - %s" %
foundry)
self.smscfoundry=1
else:
self.logger.debug("Excluding %s" % foundry)

def _getProcesses(self):
for node in self.nodes:
for foundry in self.nodes[node]:
foundry = os.path.join( self.foundrypath, node,
foundry)
for process in os.listdir(foundry):
process = os.path.join( foundry, process )
if os.path.isdir( process ):
self.logger.debug("Process found - %s" %
process )

self.nodes[node][os.path.basename(foundry)].append(os.path.basename(process))
else:
self.logger.debug("Excluding %s" % process)

Please feel free to comment and clean it up. I want it readable so I
can modify it later ;)

Mar 10 '06 #5
The parsing is good; the structure can be transformed after the parsing
is done.

The basic problem with the "reverse lookup" search is that you need to
iterate over lots of things. If you're only doing one search, that's
not too horrible But if you're going to perform multiple searches, you
can do the iteration once and cache the results. This is a trade-off
between space and time, but the space shouldn't be a problem on a
modern computer unless you've got millions of nodes.

# take the already-defined dict and make some lookup tables with
foundries and processes as keys
from sets import Set
foundry_lookup_table = {}
process_lookup_table = {}

for node, foundries in dict.iteritems():
for foundry, processes in foundries.iteritems():
if foundry not in foundry_lookup_table:
foundry_lookup_table[foundry] = Set([node])
else:
foundry_lookup_table[foundry].add(node)
for process in processes:
if node not in process_lookup_table:
process_lookup_table[process] = Set([node])
else:
process_lookup_table[process].add(node)

# Now calls to getNode will be very fast
def getNode(Foundry=None, Process=None):
if Foundry is None and Process is None:
return dict.keys() # all nodes
elif Process is None:
return list(foundry_lookup_table.get(Foundry,Set()))
elif Foundry is None:
return list(process_lookup_table.get(Process,Set()))
else:
return list(
foundry_lookup_table.get(Foundry,Set()).intersecti on(process_lookup_table.get(Process,Set()))

Mar 10 '06 #6
I made a logic error in that. Must be tired :-( Alas, there is no
undo on usenet.

Mar 10 '06 #7
rh0dium wrote:
Basically there are multiple combinatories here - I was hoping someone
could point me to a general approach. Writing the actual funtion is
not necessary - as you pointed out I can certainly do that. Here is my
problem - I did exactly as you and said OK I can

if Foundry==None and Process==None:

elif Foundy==None and Process!=None:

elif Foundy!=None and Process==None:

elif Foundy!=None and Process!=None:

But this seems very ugly... And if I want to do this for the three
areas, it seems very repetitive. I was looking for a better way to
break this down which is reusable.


First, use identity comparisons with None.
Second, I'd do it like this:

if Foundry is None:
# common ~Foundry stuff
if Process is None:
pass # ~F & ~P stuff
else:
pass # ~F & P stuff
# common ~Foundry stuff needing Process resolved
else:
# common Foundry stuff
if Process is None:
pass # F & ~P stuff
else:
pass # F & P stuff
# common ~Foundry stuff needing Process resolved

Unless there is more Process / ~Process common work, in which
case re-nest. Don't be scared to write "the obvious" in Python.

Second, once it grows to over two, think about doing things by cases:

def AllTrue(Foundry, Process, Vendor):
print 'Triple', (Foundry, Process, Vendor)
def NoVendor(Foundry, Process, Vendor):
print 'Pair', (Foundry, Process)
...
def Nothing(Foundry, Process, Vendor):
print 'Nada'
behavior = {0: AllTrue, 1:NoVendor, 2:NoProcess, 3: OnlyFoundry,
4: NoFoundry, 5:OnlyProcess, 6:OnlyVendor, 7: Nothing}
def dispatch(f, p, v):
return behavior[((f is None) * 2 + (p is None)) * 2
+ (v is None)](f, p, v)
...
dispatch('Intel', 'Silicon', None)
--Scott David Daniels
sc***********@acm.org
Mar 10 '06 #8
rh0dium wrote:
Hi all,

I have a dict which looks like this..

dict={'130nm': {'umc': ['1p6m_1.2-3.3_fsg_ms']},
'180nm': {'chartered': ['2p6m_1.8-3.3_sal_ms'], 'tsmc':
['1p6m_1.8-3.3_sal_log', '1p6m_1.8-3.3_sal_ms']},
'250nm': {'umc': ['2p6m_1.8-3.3_sal_ms'], 'tsmc':
['1p6m_2.2-3.5_sal_log', '1p6m_1.8-3.3_sal_ms']}
}

For clarification:
130nm,180nm,250nm refer to Nodes
tsmc,chartered,umc refer to Foundries
1p6m..blah, 2p6m..blah refer to Process

I want a function which can do this:

nodes = getNodes()
should return a list [130nm,180nm,250nm]

nodes = getNodes(Foundry="umc")
should return a list [130nm,250nm]

nodes = getNodes(Process="2p6m_1.8-3.3_sal_ms")
should return a list [180nm,250nm]

nodes = getNodes(Foundry="umc", Process="2p6m_1.8-3.3_sal_ms")
should return a list [250nm]

nodes = getNodes(Foundry="foo", Process="2p6m_1.8-3.3_sal_ms")
should return None

Obviously I want to extend this to Each area ( i.e., getFoundry(),
getProcess() ) but I can do that. I just don't know how to easily do
this reverse kind of look up? Can someone help me on this?


Not tested:
import pprint

data={
'130nm': {
'umc': ['1p6m_1.2-3.3_fsg_ms']
},
'180nm': {
'chartered': ['2p6m_1.8-3.3_sal_ms'],
'tsmc': ['1p6m_1.8-3.3_sal_log', '1p6m_1.8-3.3_sal_ms']
},
'250nm': {
'umc': ['2p6m_1.8-3.3_sal_ms'],
'tsmc':['1p6m_2.2-3.5_sal_log', '1p6m_1.8-3.3_sal_ms']
}
}
# ----------------------------------------------------------------------
class DataFinder(object):
def __init__(self, data):
self._data = data
self._nodes = data.keys()
self._foundries_nodes = {}
self._procs_nodes = {}
self._procs_foundries = {}

for node, foundries in data.items():
for foundry, procs in foundries.items():
self._foundries_nodes.setdefault(foundry,
[]).append(node)
for proc in procs:
self._procs_nodes.setdefault(proc, []).append(node)
self._procs_foundries.setdefault(proc,
[]).append(foundry)
self._foundries = self._foundries_nodes.keys()
self._procs = self._procs_foundries.keys()

# ------------------------------------------------------------------
# API
# ------------------------------------------------------------------
def get_nodes(foundry=None, process=None):
if foundry is None and process is None:
return self._nodes[:]
if process is None:
return self._get_nodes_for_foundry(foundry)
if foundry is None:
return self._get_nodes_for_proc(proc)
return self._get_nodes_for_foundry_and_proc(foundry, proc)

def get_foundries(node=None, process=None):
if node is None and process is None:
return self._foundries[:]
if process is None:
return self._get_foundries_for_node(node)
if node is None:
return self._get_foundries_for_proc(node)
return self._get_foundries_for_node_and_proc(node, proc)

# TODO : get_procs

#-------------------------------------------------------------------
# IMPL
# ------------------------------------------------------------------
def _get_foundries_for_node(self, node):
return self._foundries_nodes.get(node)

def _get_foundries_for_proc(self, proc):
return self._procs_foundries.get(proc)

def _get_foundries_for_node_and_proc(self, node, proc):
return list(set(self._get_foundries_for_node(node))
& set(self._get_foundries_for_proc(proc)))

# ------------------------------------------------------------------
def _get_nodes_for_foundry(self, foundry):
return self._foundries_nodes.get(foundry)

def _get_nodes_for_proc(self, proc):
return self._procs_nodes.get(proc)

def _get_nodes_for_foundry_and_proc(self, foundry, proc):
return list(set(self._get_nodes_for_foundry(foundry))
& set(self._get_nodes_for_proc(proc)))

# ------------------------------------------------------------------
# MISC
# ------------------------------------------------------------------
def _inspect(self):
ft = pprint.pformat
s = """
---
+ data :
%s
+ foundries_nodes :
%s
+ procs_nodes :
%s
+ procs_foundries :
%s
""" % (ft(self._data),
ft(self._foundries_nodes),
ft(self._procs_nodes),
ft(self._procs_foundries)
)
print s

HTH
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Mar 10 '06 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: tjland | last post by:
Okay so im working on a very simple encryption method using just loops. Kind of novel i think. Okay so first i set up a list of the alphabet with just every seperate letter, then user is prompted...
59
by: Raymond Hettinger | last post by:
Please comment on the new PEP for reverse iteration methods. Basically, the idea looks like this: for i in xrange(10).iter_backwards(): # 9,8,7,6,5,4,3,2,1,0 <do something with i> The...
2
by: John Mudd | last post by:
I must be missing something here. It's clearly faster to lookup an item directly in a dictionary than to scan through a list. So when I have a large lookup table I always load it in the form of a...
125
by: Raymond Hettinger | last post by:
I would like to get everyone's thoughts on two new dictionary methods: def count(self, value, qty=1): try: self += qty except KeyError: self = qty def appendlist(self, key, *values): try:
26
by: Alan Silver | last post by:
Hello, I have a server running Windows Server 2003, on which two of the web sites use the MegaBBS ASP forum software. Both sites suddenly developed the same error, which seems to be connected to...
2
by: John | last post by:
I am trying to design a dictionary in such a way that I can keep the interface and implementation separate. Here is my initial design. Anyone has any comments on it or suggestions on how I could...
12
by: rudysanford | last post by:
I just started messing with programming and started with Python. Part of my first project deals with translating numerical values to letters. I would like to be able to do the reverse as well,...
8
by: schaf | last post by:
Hi NG! I have a problem in my remote application. After calling a remote function the calculation will be done by the service. The calculation result will be sent to the caller (client) via...
2
by: =?Utf-8?B?c2lwcHl1Y29ubg==?= | last post by:
Hi I have a class that inherits from Generics Dictionary The string that is used for the key is passed thru-out my pgm and sometimes it has modifiers added to the key string that are used in the...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.