I was tinkering with a permutations example from a book. Following code works as intented.
perms([]) -> [[]];
perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].
And when I substitute the expressions it become this:
[ [1 | perms([2])],
[2 | perms([1])] ]
[ [1 | [[2 | perms([])]]],
[2 | [[1 | perms([])]]] ]
[ [1 | [ [2 | [[]] ] ]],
[2 | [ [1 | [[]] ] ]] ]
And this evaluates correctly to [[1,2], [2,1]].
But when I changed the base case to the empty list from a list contains an empty list:
perms([]) -> [];
It returns an empty list. When I substitute I got this.
[ [1 | [[2 | [] ]]],
[2 | [[1 | [] ]]] ]
I tried both expression with flatten but they yielded same and correct result.
[[1 | lists:flatten([[2 | lists:flatten([[]]) ]])], [2 | lists:flatten([[1 | lists:flatten([[]]) ]])]]
[[1 | lists:flatten([[2 | lists:flatten([]) ]])], [2 | lists:flatten([[1 | lists:flatten([]) ]])]].
So I couldn't figure out the difference between two expressions.
This function implements a recursive algorithm:
What are the permutations of a non-empty list? For each of the elements in the list, take the permutations of the list minus that element and prepend the element to each such permutation.
What are the permutations of an empty list? There is just one: the empty list itself, so we return a list containing one element, namely the empty list: [[]]
By changing the base case to return [] instead of [[]], you're saying:
What are the permutations of an empty list? There are zero permutations.
And then in the recursive case, you get to the step "take the permutations of..." - but there are no permutations, so there is nothing you can prepend elements to.
Related
I have a database where sentences are related to each other. I have to perform a big update on the whole database, thus I'm trying to parallelize the update.
The relevant cypher query looks like this:
match (s:Sentence)-[r:RELATED]-(t:Sentence)
return s as sentence, collect(t.embedding) as neighbours_embeddings
embedding is a list of numbers.
This returns a result like this:
---------------------------------------
| sentence | neighbours_embeddings |
---------------------------------------
| sentence1 | [[1, 2, 3], [4, 5, 6]] |
---------------------------------------
| sentence2 | [[2, 3, 5]] |
---------------------------------------
Now I wanna perform some operations on the neighbours_embeddings and set a property in the corresponding Sentence node.
I've looked at different parallelization techniques in Neo4j and as far as I understood, all of them need a list as input. But my input would be a tuple like (sentence, neighbours_embeddings). How do I achieve this?
Full query for interested folks:
match (s:Sentence)-[r:RELATED]-(t:Sentence)
with s as sentence, collect(t.embedding) as neighbours
with sentence, [
w in reduce(s=[], neighbour IN neighbours |
case when size(s) = 0 then
neighbour else [
i in range(0, size(s)-1) |
s[i] + neighbour[i]] end) |
w / tofloat(size(neighbours))
] as average
with sentence, [
i in range(0, size(sentence.embedding)-1) |
(0.8 * sentence.embedding[i]) + (0.2 *average[i])
] as unnormalized
with sentence, unnormalized, sqrt(reduce(sum = 0.0, element in unnormalized | sum + element^2)) as divideby
set sentence.normalized = [
i in range(0, size(unnormalized)-1) | (unnormalized[i] / divideby)
]
For paralelizing, apoc is your friend, specifically the apoc.periodic.iterate procedure. In your usecase you can parallelize as you are only updating a property of a single node in each row.
The resulted query would look something like:
CALL apoc.periodic.iterate("
match (s:Sentence) RETURN s",
"
match (s)-[r:RELATED]-(t:Sentence)
with s as sentence, collect(t.embedding) as neighbours
with sentence, [
w in reduce(s=[], neighbour IN neighbours |
case when size(s) = 0 then
neighbour else [
i in range(0, size(s)-1) |
s[i] + neighbour[i]] end) |
w / tofloat(size(neighbours))
] as average
with sentence, [
i in range(0, size(sentence.embedding)-1) |
(0.8 * sentence.embedding[i]) + (0.2 *average[i])
] as unnormalized
with sentence, unnormalized, sqrt(reduce(sum = 0.0, element in unnormalized | sum + element^2)) as divideby
set sentence.normalized = [
i in range(0, size(unnormalized)-1) | (unnormalized[i] / divideby)
]", {batchSize:1000, parallel:true})
You can play around with the batchSize parameter. For more information look at the docs.
I tried to use this code to scramble the characters into different characters and return a new list with those new characters. However, I keep getting errors saying : "a list but here has type char" on line 3, "a list list but given a char list" on the line 13 . Not sure how to fix this. Thanks in advance for the help.
let _scram x =
match x with
| [] -> [] // line 3
| 's' -> 'v'
| 'a' -> 's'
| 'e' -> 'o'
| '_' -> '_'
let rec scramble L P =
match L with
| [] -> P
| hd::t1 -> scramble t1 (P # (_scram hd))
let L =
let p = ['h'; 'e'; 'l'; 'l'; 'o'] //line 13
scramble p []
That's because you are calling the _scram as second operand of the (#) operator which concatenates two lists, so it infers that the whole expression has to be a list.
A quick fix is to enclose it into a list: (P # [_scram hd]), this way _scram hd is inferred to be an element (in this case a char).
Then you will discover your next error, the catch-all wildcard is in quotes, and even if it wouldn't, you can't use it to bind a value to be used later.
So you can change it to | c -> c.
Then your code will be like this:
let _scram x =
match x with
| 's' -> 'v'
| 'a' -> 's'
| 'e' -> 'o'
| c -> c
let rec scramble L P =
match L with
| [] -> P
| hd::t1 -> scramble t1 (P # [_scram hd])
let L =
let p = ['h'; 'e'; 'l'; 'l'; 'o']
scramble p []
F# code is defined sequentially. The first error indicates there is some problem with the code upto that point, the definition of _scram. The line | [] -> [] implies that _scram takes lists to lists. The next line | 's' -> 'v' implies that _scram takes chars to chars. That is incompatible and that explains the error.
Within a FOREACH statement [e.g. day in range(dayX, dayY)] is there an easy way to find out the index of the iteration ?
Yes, you can.
Here is an example query that creates 8 Day nodes that contain an index and day:
WITH 5 AS day1, 12 AS day2
FOREACH (i IN RANGE(0, day2-day1) |
CREATE (:Day { index: i, day: day1+i }));
This query prints out the resulting nodes:
MATCH (d:Day)
RETURN d
ORDER BY d.index;
and here is an example result:
+--------------------------+
| d |
+--------------------------+
| Node[54]{day:5,index:0} |
| Node[55]{day:6,index:1} |
| Node[56]{day:7,index:2} |
| Node[57]{day:8,index:3} |
| Node[58]{day:9,index:4} |
| Node[59]{day:10,index:5} |
| Node[60]{day:11,index:6} |
| Node[61]{day:12,index:7} |
+--------------------------+
FOREACH does not yield the index during iteration. If you want the index you can use a combination of range and UNWIND like this:
WITH ["some", "array", "of", "things"] AS things
UNWIND range(0,size(things)-2) AS i
// Do something for each element in the array. In this case connect two Things
MERGE (t1:Thing {name:things[i]})-[:RELATED_TO]->(t2:Thing {name:things[i+1]})
This example iterates a counter i over which you can use to access the item at index i in the array.
I got the following cypher query:
neo4j-sh$ start n=node(1344) match (n)-[t:_HAS_TRANSLATION]-(p) return t,p;
+-----------------------------------------------------------------------------------+
| t | p |
+-----------------------------------------------------------------------------------+
| :_HAS_TRANSLATION[2224]{of:"value"} | Node[1349]{language:"hi-hi",text:"(>0#"} |
| :_HAS_TRANSLATION[2223]{of:"value"} | Node[1348]{language:"es-es",text:"hembra"} |
| :_HAS_TRANSLATION[2222]{of:"value"} | Node[1347]{language:"ru-ru",text:"65=A:89"} |
| :_HAS_TRANSLATION[2221]{of:"value"} | Node[1346]{language:"en-us",text:"female"} |
| :_HAS_TRANSLATION[2220]{of:"value"} | Node[1345]{language:"it-it",text:"femmina"} |
+-----------------------------------------------------------------------------------+
and the following array:
["it-it", "en-us", "fr-fr", "de-de", "ru-ru", "hi-hi"]
How can I change the query to return just one result, where 'language' is the same as the first occurrence of the array?
If the array should be
["fr-fr","jp-jp","en-us", "it-it", "de-de", "ru-ru", "hi-hi"]
I'd need to return the Node[1346], because it is the first with a match in the language array [en-us], being no entry for [fr-fr] and [jp-jp]
Thank you
Paolo
Cypher can express arrays, and indexes into them. So on one level, you could do this:
start n=node(1344)
match (n)-[t:_HAS_TRANSLATION]-(p)
where p.language = ["it-it", "en-us", "fr-fr", "de-de", "ru-ru", "hi-hi"][0] return t,p;
This is really just the same as asking for those nodes p where p.language="it-it" (the first element in your array).
Now, if what you mean is that the language attribute itself can be an array, then just treat it like one:
$ create (p { language: ['it-it', 'en-us']});
+-------------------+
| No data returned. |
+-------------------+
Nodes created: 1
Properties set: 1
$ match (p) where p.language[0] = 'it-it' return p;
+-------------------------------------+
| p |
+-------------------------------------+
| Node[1]{language:["it-it","en-us"]} |
+-------------------------------------+
1 row
38 ms
Note the array brackets on p.language[0].
Finally, if what you're talking about is splitting your language parts into pieces (i.e. "en-us" = ["en", "us"]) then cypher's string processing functions are a little on the weak side, and I wouldn't try to do this. Instead, I'd pre-process that before inserting it into the graph in the first place, and query them as separate pieces.
I have been examining a code example and I cannot understand what is happening, I have tried to understand easier examples and get them but at this one I am getting stuck:
seq([X, X | Xs]) -> [X | seq(Xs)];
seq([X, Y | Xs]) -> [X, Y | seq(Xs)];
seq(_) -> [].
When I run it in the shell with [1,1,1,2,2,2,3] I get [1,1,2,2]. I have been trying to understand the steps by writing it on paper but I got stuck halfway trough.
I would appreciate all answers explaining me the steps happening here! :)
/Eri.
Ok, so we start with a list of [1,1,1,2,2,2,3].
On the first call to seq, erlang will match the first two elements 1 and 1 to the first "clause" of seq - seq([X, X | Xs]).
This will initialize the list that will become the final return value, [1, seq(Xs)]. Now at this point Xs will be bound to the value [1,2,2,2,3]. If you're wondering why there aren't two 1's at the beginning of the Xs list it's because we matched/bound two of them on [X, X | Xs].
Return value = [1 | ?] (? is the remaining recursion to be evaluated)
Xs = [1,2,2,2,3]
On the second call to seq, erlang will match the first two elements of the input list 1 and 2 to the second clause seq([X, Y | Xs]). We then "return" the list [X, Y] or [1, 2] from this run, and call the next iteration with Xs = [2,2,3].
Return value = [1 | [1, 2 | ?]] <- See how recursion nests the lists?
Xs = [2,2,3]
On the third call, the first two elements are the same again, so erlang runs the first clause again. seq([X, X | Xs]) -> [X | seq(Xs)]. We return a single 2 value as part of the evaluation, and call seq([3]).
Return value = [1 | [1, 2 | [2 | ?]]]
Xs = [3]
At last, the final case. Our list of [3] doesn't match [X, X | Xs] nor [X, Y, Xs], so erlang will run our catch-all: seq(_) -> []. _ will match anything, and not bind the value to any local variables, so all we do here is return an empty list [].
Our final return value then is: [1 | [1, 2 | [2 | []]]]. If you evaluate this into your erl repl, you'll see it's the same as the list [1,1,2,2], the later is syntactic sugar for the former.
Tracing can help you a little bit:
1> dbg:tracer().
{ok,<0.35.0>}
2> dbg:p(self(), [c]).
{ok,[{matched,nonode#nohost,1}]}
3> dbg:tpl({test, seq, 1}, [{'_',[],[{return_trace}]}]).
{ok,[{matched,nonode#nohost,1},{saved,1}]}
4> test:seq([1, 1, 1, 2, 2, 2, 3]).
(<0.33.0>) call test:seq([1,1,1,2,2,2,3])
(<0.33.0>) call test:seq([1,2,2,2,3])
(<0.33.0>) call test:seq([2,2,3])
(<0.33.0>) call test:seq([3])
(<0.33.0>) returned from test:seq/1 -> []
(<0.33.0>) returned from test:seq/1 -> [2]
(<0.33.0>) returned from test:seq/1 -> [1,2,2]
(<0.33.0>) returned from test:seq/1 -> [1,1,2,2]
[1,1,2,2]