Find the elements between matching elements in two lists - haskell

Let's say I have two lists of words called query and sentence. What I want to find is, for each pair of consecutive words in the query, a list of all the words between those two in the sentence. Also, if the first word of the query is not the first word of the sentence, the result should include a list with all the words in the sentence up to that one (and the same goes for the last word in the query).
So for example, if the query and the sentence looked like this:
query = ["like", "with"]
sentence = ["I", "like", "coffee", "with", "sugar", "and", "milk"]
then the result should be:
result = [["I"], ["coffee"],["sugar", "and", "milk"]]
However, there might be more than one way to make this match, depending on the sentence and query. For example:
query = ["bear", "my"]
sentence = ["I", "cannot", "bear", "when", "my", "bear", "leaves", "my", "house"]
In this case, there are many valid results:
result1 = [["I", "cannot"], ["when"], ["bear", "leaves", "my", "house"]]
result2 = [["I", "cannot"], ["when", "my", "bear", "leaves"], ["house"]]
result3 = [["I", "cannot", "bear", "when", "my"], ["leaves"], ["house"]]
So, what I need is a list of all the possible results for a given sentence and query. I've been trying to come up with a solution for a while now, but I can't work out how to find all possible combinations without making a mess of my code.

This is an exercise in non-determinism, which is modeled by the [] monad.
Start by writing a function
foo :: String -> [String] -> [([String], [String])]
that can split sentence into exactly two parts based on a given word. That is,
foo "bear" sentence == [
(["I", "cannot"], ["when", "my", "bear", "leaves", "my", "house"]),
(["I", "cannot", "bear", "when", "my"], ["leaves", "my", "house"]),
]
Given a list of split words, you recursively split the second list using the next split word.
do_it [] _ = []
do_it (q:qs) words = do
(x, y) <- foo q words
return (x : do_it qs words)

Related

Concat a sublist of strings intro string elements of a list

Say I have a list of substrings [["hello", "how", "are", "you?"], ["I'm", "doing", "great"]] and I wanted to create a list of ["hello how are you?", "I'm doing great"] how would one go about this?
I've tried
sum(mylist, [])
>> ["hello", "how", "are", "you?", "I'm", "doing", "great"]
and also
new_list = []
for i in mylist:
new_list += i
>> ["hello", "how", "are", "you?", "I'm", "doing", "great"]
And neither seem to what I want it to do. I suspect that I need to join the subarrays first, and then append them maybe to a new list. Any thoughts or suggestions?
Once more the goal is to take:
[["hello", "how", "are", "you?"], ["I'm", "doing", "great"]]
and make it into:
["hello how are you?", "I'm doing great"]
One simple way to do it is use list comprehension:
nested_lists = [["hello", "how", "are", "you?"], ["I'm", "doing", "great"]]
joined_list = [' '.join(str_list) for str_list in nested_lists]
print(joined_list)
# Outputs ['hello how are you?', "I'm doing great"]
essentially list comprehension merges a loop and list construction in the same construct - see line 2.
my_list = [["hello", "how", "are", "you?"], ["I'm", "doing", "great"]]
new_list = []
for mini_list in my_list:
new_list.append(' '.join(mini_list)
This would therefore, take each item from that list which itself is a list and join them.
It will then append it to what I'm calling the new_list to give you the result you want.
Just mapping all sublists with ' '.join:
new_list = [*map(' '.join, mylist)]
Or one character shorter:
*new_list, = map(' '.join, mylist)

I need to add the items from list A to list B, only when the item already exists in list B

I need to add all the items in list A in to list B, if and only if the items already exist in list B, even if there are multiple items that are same in list A. How can I do this? Right now, it stops after the first of the same words. Say for example, List A is [the, a, sure, book, is, the, best], and list B is [the, rock], I need to add the two "the"s in list A to list B, to make a total of three "the"s in list B
It's for a beginner's class in python. I've tried different formats of the for loop, but it doesn't seem to work. There is a for loop before this, that creates the list B, I think it maybe because of the back to back for loops.
for word in list_a:
if word[0].isupper() == True:
list_b.append(word)
list_b = [word.lower() for word in list_b]
for word in list_a:
if word in list_b:
list_b.append(word)
list_b = [word.capitalize() for word in list_b]
The second for loop is the one giving me trouble. I have pasted the larger code which I am trying to work with. So my main objective is to first separate the words that are capitalized in list A in to list B.
Then lowercase list B, so I can find the same words in list A that are not capitalized, and then add those to list B as well. Then capitalize all of list B again to print the count.
I know that there is an easier way to do this, where I can just make the original string lowercase and then work from there. However, in this case I need to keep track of the words that were originally capitalized, because when I print the words with their total counts, the words that were originally capitalized, need to print in their capitalized form rather than the lowercase form.
Therefore, the expected outcome I am looking for is list B as [the, rock, the, the].
a = ['the', 'a', 'sure', 'book', 'is', 'the', 'best']
b = ['the', 'rock']
b = b + [text for text in a if text in b]
list_b = list_b + ([x for x in list_a if x in list_b])
result:
['the', 'rock', 'the', 'the']

Return a dictionary with keys that are the first letter of a word and lists of those words?

I want to write a function that takes a list of words and keys and outputs those keys as dictionary keys with any words starting with that letter attached.
How could this be achieved using simple python 3 code?
eg. takes (['apples', 'apple', 'bananna', 'fan'], 'fad')
returns {'a' : ['apple', 'apples'], 'f' : ['fan']}
so far i have tried:
def dictionary(words, char_keys)
char_keys = remove_duplicates(char_keys)
ret = {}
keys_in_dict = []
words = sorted(words)
for word in words:
if word[0] in char_keys and word[0] not in keys_in_dict:
ret[word[0]] = word
keys_in_dict.append(word[0])
elif word[0] in keys_in_dict:
ret[word[0]] += (word)
return ret
This gives kinda the right output but it the output is in a single string rather than a list of strings.(the def is not indented properly i know)
If the input is a list of strings, you can check if the char is in the dict, if yes, append the word, otherwise add a list with the word:
def dictionary(inpt):
result = {}
for word in inpt:
char = word[0]
if char in result:
result[char].append(word)
else:
result[char] = [word]
return result
The modern way to do this is to use a collections.defaultdict with list as argument.
def dictionary(inpt):
result = defaultdict(list)
for word in inpt:
result[word[0]].append(word)
return result
Not sure if your list of inputs are consisted with only strings or it can also include sub-lists of strings (and I'm not so sure why "fad" disappeared in your example). Obviously, in the latter scenario it will need some more effort. For simplicity I assume if contains only strings and here's a piece of code which hopefully points the direction:
d = {}
for elem in input_list[0]:
if elem[0] in input_list[1]
lst = d.get(elem[0], [])
lst.append(elem)
d[elem] = lst

Cartesian product from list of Strings

To answer this question you need to write code that will produce
a list of strings that contains all combinations that can be made
from two input lists by taking an element from the first list and
following it by an element of the second list (with a space in between).
The ordering of elements in the new list should be determined
primarily the the ordering in the first list and secondarily
(for elements with the same same first part) by the ordering
of the second list.
So, if the first input is of the form: A, B, .. X
and the second is of the form: 1, 2, .. n
the output would be of the form:
["A 1", "A 2", .. "An", "B 1", "B 2", .. "Bn", .. "X 1", "X 2", .. "Xn"]
(where the ".." indicates there can be more elements in between).
NOTES:
1. There can be different numbers of elements in the two lists.
2. If the first list has M elements and the second list has N elements,
then the output list should have M*N elements.
""" )
print("INPUT:")
listA=[] #Creating a list
listB=[]#Creating a second list
listC=[]
while True:
print("add element y to continue")
if input()!='y':
break
else:
print("keep adding or x to break" )
while True:
if input=='x':
break
else:
input_listA = input( "Enter first comma separated list of strings: " )
print(n)
listA.append(input_listA)
print(input_listA)
print(listA)
if input=='x':
break
else:
input_listB=input( "Enter second comma separated list of int: " )
input_listB.split()
listB.append(input_listB)
break
however when i right words it for instance ["black ham ", "twice mouse", "floating cheese", "blue elf", "electric elf", "floating elf"] in the calculation for the cartesian product will be calculatin characters not words like 'b', 'l','a','c','k' how can i make the strings words inside the list and also how can i print it in the form of i mean without commas because as you can see i input delimiter along the strings
Try this:
import itertools
a = input("Enter first comma separated list of strings: ")
b = input("Enter second comma separated list of strings: ")
result = []
for i in itertools.product(a.split(","), b.split(",")):
result.append("".join(map(str, i)))
print(result)
Result:
~ $ python3 test.py
Enter first comma separated list of strings: aa,bb
Enter second comma separated list of strings: 1,2,3
['aa1', 'aa2', 'aa3', 'bb1', 'bb2', 'bb3']
If you'd rather like a space between the two words in each pair, change
result.append("".join(map(str, i)))
to
result.append(" ".join(map(str, i)))
Output:
['aa 1', 'aa 2', 'aa 3', 'bb 1', 'bb 2', 'bb 3']

Assign splited string to array in elixir

I am new in elixir development. I have problem with parsing of string in elixir. Assume that I have string "Hello World from the hell". I know that I can split this like this String.split("Hello World from the hell"). I would like to know is the anyway to assign element of this string to list in elixir?
String.split/1 returns a list - one of Elixir's fundamental data structures, along with maps and tuples. A list is your go-to basic collection in Elixir. Even though internally it's a linked list, you can perform all sorts of operations on it using functions from the Enum module:
$ iex
iex(1)> ls = String.split("Hello World from the hell")
["Hello", "World", "from", "the", "hell"]
iex(2)> i ls
Term
["Hello", "World", "from", "the", "hell"]
Data type
List
Reference modules
List
iex(3)> Enum.take(ls, 2)
["Hello", "World"]
iex(4)> Enum.at(ls, 4)
"hell"
iex(5)> [l0, l1, l2, l3, l4] = ls
["Hello", "World", "from", "the", "hell"]
iex(6)> l4
"hell"
iex(7)> Enum.take(ls, 4) ++ ["iex", "shell"]
["Hello", "World", "from", "the", "iex", "shell"]
As you can see Enum.at/3 gives you something similar to the a[i] style array access.
If you're worried about the efficiency of finding an element in your list - for example your input string is going to be something much longer than "Hello World from the hell" and you'll be getting elements from it by index many times, essentially traversing it each time, you can build a map from it instead, and look the words by indices efficiently:
iex(8)> with_indices = Enum.with_index(ls)
[{"Hello", 0}, {"World", 1}, {"from", 2}, {"the", 3}, {"hell", 4}]
iex(9)> indices_and_words = Enum.map(with_indices, fn({a, b}) -> {b, a} end)
[{0, "Hello"}, {1, "World"}, {2, "from"}, {3, "the"}, {4, "hell"}]
iex(10)> map = Map.new(indices_and_words)
%{0 => "Hello", 1 => "World", 2 => "from", 3 => "the", 4 => "hell"}
iex(11)> map[0]
"Hello"
iex(12)> map[4]
"hell"

Resources