Invalid input 'r': expected 't/T' - neo4j

Getting the folllowing error:
Neo.ClientError.Statement.SyntaxError: Invalid input 'r': expected
't/T' (line 4, column 9 (offset: 116)) "sum(if sr.WScore > sr.LScore
then 1 else 0 ) as wins"
Is my logic right????
MATCH (t:Teams),(sr:SeasonResults)
WHERE sr.WTeamID=t.TeamID and t.TeamName="x"
RETURN count(wins),
sum(if sr.WScore > sr.LScore then 1 else 0 ) as wins

Use CASE not IF
sum(CASE WHEN sr.WScore > sr.LScore THEN 1 ELSE 0 )

A WITH or RETURN clause cannot both assign to a variable (like wins) AND use the same variable. So, a clause like RETURN COUNT(wins), SUM(...) AS wins is not supported.
However, if your use case is just to count the number of times in which a related SeasonResults node had WScore > LScore, you don't need to use COUNT(), and this should be sufficient:
MATCH (t:Teams), (sr:SeasonResults)
WHERE sr.WTeamID=t.TeamID and t.TeamName="x"
RETURN SUM(CASE WHEN sr.WScore > sr.LScore THEN 1 END) AS wins

I think if you take the count of SeasonResults where sr.WTeamID=t.TeamID will give you the required wins count.
I am assuming WTeamID is the ID of the winning team, so when this team's ID is equal to WTeamID of SeasonResults implies win for this team. And the count of all such a SeasonResults will be total wins for this team.
You can structure the query for the same as:
MATCH (t:Teams)
WHERE t.TeamName="x"
WITH t
MATCH (sr:SeasonResults)
WHERE sr.WTeamID=t.TeamID
RETURN count(sr) AS wins

Related

Finding the consecutive win in Cypher query language

from fig we can see that Arsenal have won three match consecutively but I could not write the query.
Here is a query that should return the maximum number of consecutive wins for Arsenal:
MATCH (a:Club {name:'Arsenal FC'})-[r:played_with]-(:Club)
WITH ((CASE a.name WHEN r.home THEN 1 ELSE -1 END) * (TOINT(r.score[0]) - TOINT(r.score[1]))) > 0 AS win, r
ORDER BY TOINT(r.time)
RETURN REDUCE(s = {max: 0, curr: 0}, w IN COLLECT(win) |
CASE WHEN w
THEN {
max: CASE WHEN s.max < s.curr + 1 THEN s.curr + 1 ELSE s.max END,
curr: s.curr + 1}
ELSE {max: s.max, curr: 0}
END
).max AS result;
The WITH clause sets the win variable to true iff Arsenal won a particular game. Notice that the ORDER BY clause converts the time property to an integer, because the ordering of numeric strings does not work properly if the strings could be of different lengths (I am being a bit picky here, admittedly). The REDUCE function is used to calculate the maximum number of consecutive wins.
======
Finally, here are some suggestions for some improvements to your data model. For example:
It looks like your played_with relationship always points from the home team to the away team. If so, you can get rid of the redundant home and away properties, and you can also rename the relationship type to HOSTED to make the direction of the relationship more clear.
The scores and time should be stored as integers, not strings. That would make your queries more efficient, and easier to write and understand.
You could also consider splitting the scores property into two scalar properties, say homeScore and awayScore, which would make your code more clear. There seems to be no advantage to storing the scores in an array.
If you made all the above suggested changes, then you would just need to change the beginning of the above query to this:
MATCH (a:Club {name:'Arsenal FC'})-[r:HOSTED]-(:Club)
WITH ((CASE a WHEN STARTNODE(r) THEN 1 ELSE -1 END) * (r.homeScore - r.awayScore)) > 0 AS win, r
ORDER BY r.time
...

Neo4j List Consecutive

I am currently working with a football match data set and trying to get Cypher to return the teams with the most consecutive wins.
At the moment I have a collect statement which creates a list i.e. [0,1,1,0,1,1,1] where '0' represents a loss and '1' represents a win. I am trying to return the team with the most consecutive wins.
Here is what my code looks like at the moment:
MATCH(t1:TEAM)-[p:PLAYS]->(t2:TEAM)
WITH [t1,t2] AS teams, p AS matches
ORDER BY matches.time ASC
UNWIND teams AS team
WITH team.name AS teamName, collect(case when ((team = startnode(matches)) AND (matches.score1 > matches.score2)) OR ((team = endnode(matches)) AND (matches.score2 > matches.score1)) then +1 else 0 end) AS consecutive_wins
RETURN teamName, consecutive_wins
This returns a list for each team showing their win / lose record in the form explained above (i.e. [0,1,0,1,1,0])
Any guidance or help in regards to calculating consecutive wins would be much appreciated.
Thanks
I answered a similar question here.
The key is using apoc.coll.split() from APOC Procedures, splitting on 0, which will yield a row per winning streak (list of consecutive 1's) as value. The size of each of the lists is the number of consecutive wins for that streak, so just get the max size:
// your query above
CALL apoc.coll.split(consecutive_wins, 0) YIELD value
WITH teamName, max(size(value)) as consecutiveWins
ORDER BY consecutiveWins DESC
LIMIT 1
RETURN teamName, consecutiveWins
Your use case does not actually require the detection of the most consecutive 1s (and it also does not need to use UNWIND).
The following query uses REDUCE to directly calculate the maximum number of consecutive wins for each team (consW keeps track of the current number of consecutive wins, and maxW is the maximum number of consecutive wins found thus far):
MATCH (team:TEAM)-[p:PLAYS]-(:TEAM)
WITH team, p
ORDER BY p.time ASC
WITH team,
REDUCE(s = {consW: 0, maxW: 0}, m IN COLLECT(p) |
CASE WHEN (team = startnode(m) AND (m.score1 > m.score2)) OR (team = endnode(m) AND (m.score2 > m.score1))
THEN {consW: s.consW+1, maxW: CASE WHEN s.consW+1 > s.maxW THEN s.consW+1 ELSE s.maxW END}
ELSE s
END).maxW AS most_consecutive_wins
RETURN team.name AS teamName, most_consecutive_wins;

FILTER by two condition then SUM the results

I not sure if I understand how FILTER is working.
I would like to SUM only the results that satisfy both conditions in the FILTER and get 8+10=18, but it seems I'm getting 8+9+10=27 as if the first condition is ignored.
Both =SUM(FILTER(E1:E10,MATCH(D1:D10, G1:G4), E1:E10 > 7)) and =SUM(FILTER(E1:E10,MATCH(D1:D10, G1:G4) * (E1:E10 > 7))) return 27
Have any ideas?
Here is an example and a screenshot
The crucial thing is putting the third argument into the Match function to specify an exact match
=SUM(FILTER(E1:E10,MATCH(D1:D10, G1:G4,0), E1:E10 > 7))
Otherwise you get the position of the largest value less than or equal to the lookup value: e.g. for "G" you would get a match with "D" which would return 4. So the Match function in your original formula always returns a number >=1 which is treated as True.
It's interesting that the above formula works actually because a non-match will return #N/A but apparently it's treated as false - I don't know if this is documented.
I would always put
=SUM(FILTER(E1:E10,isnumber(MATCH(D1:D10, G1:G4,0)), E1:E10 > 7))
to make it clearer.

How to determine if sum of any given consecutive array elements is equal to a given number in ruby?

I am attempting a coding problem which asks me to print "YES" if the sum of any consecutive array numbers is equal to the given number and "NO" if none.
Here is the question:
Prateek wants to give a party to his N friends on his birthday, where each friend is numbered from 1 to N. His friends are asking for a gift to come to the party, instead of giving him one. The cost of the gifts are given in the array Value where ith friend asks for a gift which has a cost Costi.
But, Prateek has only X amount of money to spend on gifts and he wants to invite his friends which are in continuous range such that sum of the cost of the gifts of those friends will be exactly equal to X.
If he can invite his friends, who can satisfy the above condition then, print YES otherwise print NO.
Input:
The first line contains a single integer T, denoting the number of test cases. In each test case, the following input will be present: - The next line contains two space-separated integers N and X, where N represents the number of friends and X represents amount of money which Prateek can spend on gifts.
- Next N line contains N integers, where ith line contains ith integer, which represents the Costi .
Ouput
Output exactly T lines, each containing the answer to the corresponding test case .
Constraints:
1 <= T <= 10
1 <= N , Costi <= 106
1 <= X <= 1012
SAMPLE INPUT
1
5 12
1
3
4
5
2
SAMPLE OUTPUT
YES
Explanation
In the sample input, T is equal to 1. So, accordingly, in next line, values of N and X are given which are 5 and 12 respectively. In the next 5 lines, you have costi asked by ith friend. As friends numbered from 2 to 4 (inclusively) have gifts value which are {3, 4, 5}, and their sum equals to 12 - that is, the given value of X. So, the answer is YES.
my solution is here
b = Array.new
a = Array.new
t = gets.to_i
if t >= 0 && t <= 10
t.times do
n, x = gets.chomp.split.map(&:to_i)
n.times do
a << gets.to_i
end
(1..a.length).each do |num|
a.each_cons(num).each do |pair|
if pair.inject(:+) == x
b << "YES"
else
b << "NO"
end
end
end
if b.include?("YES")
puts "YES"
else
puts "NO"
end
end
end
Although they have accepted my answer, it does not pass all the test cases, hence I am not satisfied.Can someone help me with a correct, more efficient and elegant solution?
Have a look at each_cons:
array = [1,2,3,4,5]
number = 5
array.each_cons(2) { |pair| puts 'YES' if pair.inject(:+) == number }
#=> 'YES'
number = 10
array.each_cons(2) { |pair| puts 'YES' if pair.inject(:+) == number }
#=> nil
Or when you want to return 'YES' or 'NO':
array.each_cons(2).any? { |pair| pair.inject(:+) == number } ? 'YES' : 'NO'
I suggest that you split your answer into several parts:
Reading input from the user
Determining whether an array contains a consecutive subarray that sums to a given number
Printing YES or NO.
Your code is difficult to read because all these responsibilities are intertwined. Point 2 is crucial. To play nicely with points 1 and 3 it can be solved with a function that accepts an array of numbers and the desired sum as arguments and returns true if there's a consecutive subarray with the desired sum and false otherwise.
The simplest algorithm looks at all subarrays, computes their sums and compare with the desired sum.
def consecutive_sum?(array, sum)
(0...array.size).each do |start|
(start...array.size).each do |stop|
return true if array[start..stop].inject(&:+) == sum
end
end
false
end
start and stop mark the beginning and end of the subarray. Array#inject is used to compute the sum of the subarray.
I'll leave points 1 and 3 to you.

SET in combination with CASE statement in cypher

I am tryin to set two different relationship properties to a count, with a case construct depending on the value of another relationship property. There is a console at http://console.neo4j.org/?id=rt1ld5
the cnt column contains the number of times r.value occurs. The two first rows of the initial query in the console indicate that the term "Car" is linked to 1 document that is considered relevant, and to two documents that are considered not relevant.
I want to SET a property on the [:INTEREST] relation between (user) and (term) with two properties, indicating how many times an interest is linked to a document that is considered relevant or not. So for (John)-[r:INTEREST]->(Car) I want r.poscnt=1 and r.negcnt=2
I.m struggling with the CASE construct. I tried various ways, this was the closest I got.
MATCH (u:user)-[int:INTEREST]->(t:term)<-[:ISABOUT]-(d:doc)<- [r:RELEVANCE]-(u)
WITH int, t.name, r.value, count(*) AS cnt
CASE
WHEN r.value=1 THEN SET int.poscnt=cnt
WHEN r.value=-1 THEN SET int.negcnt=cnt
END
But it's returning an error
Error: Invalid input 'A': expected 'r/R' (line 3, column 2)
"CASE"
^
This did it! Also see console at http://console.neo4j.org/?id=rq2i7j
MATCH (u:user)-[int:INTEREST]->(t:term)<-[:ISABOUT]-(d:doc)<-[r:RELEVANCE]-(u)
WITH int, t,
SUM(CASE WHEN r.value= 1 THEN 1 ELSE 0 END ) AS poscnt,
SUM(CASE WHEN r.value= -1 THEN 1 ELSE 0 END ) AS negcnt
SET int.pos=poscnt,int.neg=negcnt
RETURN t.name,int.pos,int.neg
Is it important for you to keep positive and negative count separate? It seems you could have a score property summing positive and negative values.
MATCH (u:user)-[int:INTEREST]->()<-[:ISABOUT]-()<-[r:RELEVANCE]-(u)
SET int.score = SUM(r.value)
RETURN t.name, int.score
You already seem to have found a working solution but I'll add a note about CASE as I understand it. While CASE provides branching, I think it's correct to say that it is an expression and not a statement. It resembles a ternary operator more than a conditional statement.
As the expression
a > b ? x : y;
is resolved to a value, either x or y, that can be used in a statement, so also
CASE WHEN a > b THEN x ELSE y END
resolves to a value. You can then assign this value
result = CASE WHEN a > b THEN x ELSE y END
Your original query used the CASE expression like a conditional statement
CASE WHEN a > b THEN result = x ELSE result = y END
which resembles if-else
if a > b { result = x; } else { result = y; }
Someone may want to correct the terminology, the point is that in your working query you correctly let CASE resolve to a value to be used by SUM rather than put a conditional assignment inside CASE.

Resources