Find an element in an irregular list in python - list

I have the following class
class A:
def __init__(self, elements):
self.elements = elements
I need to write a function that takes two instances of it, and finds if instance 1 is in the elements of instance 2. This is an irregular list, because those elements contain more instances of A to an arbitrary depth.
I want something along those lines:
def is_element_in(instanceA1, instanceA2):
found = False
for inherit in instanceA2.instanceof.inherits:
if instanceA1 == inherit:
found = True
else:
n_inherit(instanceA1, inherit)
return found
What's the best way to write this? I read some answers about flattening the list. I don't know if it's the best idea here, because I have to access fields to get my list of elements. Any python libraries that can be used here?

A possible solution is
def is_element_in(items, element):
for item in items:
if item == element:
return True
if isinstance(item, list) and is_element_in(item, element):
return True
return False
items = [[1, 2], [3], [[4], 5]]
print(is_element_in(items, 4))
print(is_element_in(items, 0))
Prints
True
False

Related

How to manipulate and compare lists using Groovy

I have 3 lists that I need to compare and manipulate. Here are the lists, for example:
def list1 = ['abc', '123','789'];
def list2 = ['456', 'abc', '123'];
def list3 = ['mil', 'len', 'nium'];
I need to compare values of list1 and list2 and if they are the same, I need to return the corresponding item with the same index of list1 found in list3.
Using the example above, since list1[0] and list2[1] are the same, I need to return the list3 value, 'mil'.
The lists' value will also be dynamic so how will I be able to do it in groovy?
You can read about it on Groovy Docs. You can find common elements by
def commons = collection1.intersect(collection2)
and find element in third list using index from first list by indexOf.
It may be useful as well Comparing lists
Something like
def commons = list1.intersect(list2)
def indexes = []
commons.each {
indexes << list1.indexOf(it)
}
def values = []
indexes.each {
values << list3[it]
}
Of course it can be done in many ways, easier, but it works too in some cases

How to check if unordered lists have exactly the same elements without using python methods. (need to use loops). In python

list1 = ['a','b','c','d']
list2 = ['b','c','d','a']
I have these two unordered lists and want to check if both have EXACTLY the same elements. Don't want to use set() or sorted() methods. But use looping to loop through both lists.
Keep it simple, without any helper function or list comprehension:
list1 = ['a','b','c','d']
list2 = ['b','c','d','a']
def same_lists(li1, li2):
if len(li1) != len(li2): # if the length of the lists is different than they are not equal so return false
return False
else:
for item1 in li1:
if item1 not in li2:
return False # if there is one item in li1 that is not in li2 than the lists are not identical so return false
for item2 in li2:
if item2 not in li1:
return False # same as three rows up
return True # if we didn't returned false for the whole list, than the lists are identical and we can return true.
print (same_lists(list1,list2))
This should work:
common_elements = [x for x in list1 if x in list2]
if len(list1) == len(list2) == len(common_elements):
print("EXACT SAME ELEMENTS")
else:
print("DIFFERENT ELEMENTS")
If you sort the elements first, or keep track as you encounter them, e.g. in another container, you can hand roll some solutions.
If you insist on avoiding this you need to check everything in the first list is in the seocnd and vice versa.
def same_lists(li1, li2):
if len(li1) != len(li2):
return False
else:
for item in li1:
if item not in li2:
return False
for item in li2:
if item not in li1:
return False
return True
This returns True for list1 = ['a','b','c','d'] compared with list2 = ['b','c','d','a'] and False for list3 = ['b','c','d','a', 'a'] and list4 = ['b','c','d','a', 'z'].
This is quadratic - we've compared everything with everything else (with a small optimisation checking the lengths first). We have to go through BOTH lists comaparing with the other list.
It would be quicker to sort first.

how to find whether this python list within list contains duplicates or not?

I have the following python list :-
a=[['t1', ['a', 'c']], ['t2', ['b']], ['t2', ['b']]]
now it contains duplicate lists within it ['t2', ['b']] 2 times
I want to return true if the list contains duplicates.
Can anyone please help me how to do so ?
I tried to use the set function but it is not working here !
If you are free to represent your list a as a list of tuples/records:
b = [(item[0], tuple(item[1])) for item in a]
(or, in the first place):
a = [('t1', ('a', 'c')), ('t2', ('b')), ('t2', ('b'))]
Then the items become hashable and you can use collections.Counter:
from collections import Counter
c = Counter(b)
So you can find duplicates like:
duplicated_items = [key for key, count in c.iteritems() if count > 1]
(Or you can use set):
has_duplicates = len(set(b)) < len(b)
If your aim is to remove duplicates, this answer might be helpful:
unique_a = [i for n, i in enumerate(a) if i not in a[:n]]
You can rewrite it this way:
has_duplicates = lambda l: True in [(i in l[:n]) for n, i in enumerate(l)]
You can call it this way:
has_duplicates(a) # True

Mapping a list of inputs to the lowest level of nested lists

I have a class in Python, which stores more of its kind inside of itself, as a jagged tree structure. The highest and middle layers don't store any data, but the lowest level does. I have a list such as [8, 2, 5, 3], and I want to assign each value to its corresponding slot at the lowest level of the tree: Each node can have a different number of connections downwards, and there can be any number of layers. My problem is, I can't use the traverse function presented in similar questions because I am assigning multiple values, and I can't easily get the index of each value at the bottom. Here is the node class:
class Node(object):
def __init__(self, branches):
self.branches = branches # This is a list of Node objects
self.value = 0
The branch list contains more Nodes, which have lists of Nodes themselves. The value defaults to 0, but as stated before will have a list mapped to them later on. Here is an example of how to create a tree, and what I want to do:
tree = Node([
Node([
Node([
None # This node's value is 1
]),
Node([
None # This node's value is 2
])
]),
Node([
Node([
None # This node's value is 3
]),
Node([
None # This node's value is 4
])
])
])
tree.set_inputs([1, 2, 3, 4]) # See above comments, this is what I want
How can I accomplish this? My only idea is a recursive function that turns the index of the input into a binary (this may change based on number of branches) number such as 0100110 that determines which direction to take at each recurse by indexing its branches:
# In the example above: b0 -> b1 -> b0 -> b0 -> b1 -> b1 -> b0.
If this is the way to go about this, I need some help implementing it. Otherwise, any help regarding my problem is appreciated.
A depth-first search can be done in such a way as to yield the leaf nodes of the tree in order from left-to-right or right-to-left, depending on how it is implemented. First, I'm going to add a name attribute and a __repr__ to your Node to make it easier to see what is happening:
class Node(object):
def __init__(self, name, branches):
self.branches = branches # This is a list of Node objects
self.value = 0
self.name = name
def __repr__(self):
return '<Node {}>'.format(self.name)
Now we'll define two functions. The first yields the nodes in a depth-first search:
from collections import deque
def dfs(root):
stack = deque([root])
while stack:
node = stack.pop()
yield node
if node.branches is not None:
for child in reversed(node.branches):
stack.append(child)
Note some things about this code. First, we iterate over the reversed children of the node. This results in the leaves being yielded from left-to-right. If we remove reversed, the leaves will be iterated over from right-to-left. Also, note that perhaps a cleaner representation for a leaf node without any children is to assign an empty iterable, such an empty tuple, to node.branches. Then the node.branches is not None check can be removed completely.
The above code generates all nodes, of course. We just want the leaves:
def leaves(root):
for node in dfs(root):
if node.branches is None:
yield node
Let's test it out. Here's a simple tree:
# g
# / \
# / \
# e f
# /\ /\
# a b c d
a, b, c, d = [Node(name, None) for name in 'abcd']
e = Node('e', (a,b))
f = Node('f', (c,d))
g = Node('g', (e,f))
And let's list the leaves:
>>> list(leaves(g))
[<Node a>, <Node b>, <Node c>, <Node d>]
Note that they are in order from left-to-right. Now assigning values is easy:
values = [1, 2, 3, 4]
for leaf, value in zip(leaves(g), values):
leaf.value = value
So that:
for node in (a, b, c, d):
print(node.name, node.value)
gives:
a 1
b 2
c 3
d 4

Get the first element of a list idiomatically in Groovy

Let the code speak first
def bars = foo.listBars()
def firstBar = bars ? bars.first() : null
def firstBarBetter = foo.listBars()?.getAt(0)
Is there a more elegant or idiomatic way to get the first element of a list, or null if it's not possible? (I wouldn't consider a try-catch block elegant here.)
Not sure using find is most elegant or idiomatic, but it is concise and wont throw an IndexOutOfBoundsException.
def foo
foo = ['bar', 'baz']
assert "bar" == foo?.find { true }
foo = []
assert null == foo?.find { true }
foo = null
assert null == foo?.find { true }
--Update Groovy 1.8.1
you can simply use foo?.find() without the closure. It will return the first Groovy Truth element in the list or null if foo is null or the list is empty.
You could also do
foo[0]
This will throw a NullPointerException when foo is null, but it will return a null value on an empty list, unlike foo.first() which will throw an exception on empty.
Since Groovy 1.8.1 we can use the methods take() and drop(). With the take() method we get items from the beginning of the List. We pass the number of items we want as an argument to the method.
To remove items from the beginning of the List we can use the drop() method. Pass the number of items to drop as an argument to the method.
Note that the original list is not changed, the result of take()/drop() method is a new list.
def a = [1,2,3,4]
println(a.drop(2))
println(a.take(2))
println(a.take(0))
println(a)
*******************
Output:
[3, 4]
[1, 2]
[]
[1, 2, 3, 4]