列表表达式

列表表达式允许您在 Cypher® 中操作和查询 LIST(列表)值。

有关计算结果为 LIST 值的更多表达式,请参阅 列表函数
有关如何使用 IN 运算符检查 LIST 中成员资格的信息,请参阅 谓词 → 列表运算符

示例图

以下图表用于下方的示例

list expressions graph

要重新创建该图,请在空的 Neo4j 数据库中运行以下查询

CREATE (alice:Person {name:'Alice', age: 65, role: 'Project manager', skills: ['Java', 'Python']}),
       (cecil:Person {name: 'Cecil', age: 25, role: 'Software developer', skills: ['Java', 'Python']}),
       (cecilia:Person {name: 'Cecilia', age: 31, role: 'Software developer', skills: ['JavaScript', 'TypeScript']}),
       (charlie:Person {name: 'Charlie', age: 61, role: 'Security engineer', skills: ['C++', 'Python']}),
       (daniel:Person {name: 'Daniel', age: 39, role: 'Director', skills: ['Ruby', 'Go']}),
       (eskil:Person {name: 'Eskil', age: 39, role: 'CEO', skills: ['Java', 'C++', 'Python']}),

       (cecil)-[:WORKS_FOR]->(alice),
       (cecilia)-[:WORKS_FOR]->(alice),
       (charlie)-[:WORKS_FOR]->(daniel),
       (alice)-[:WORKS_FOR]->(daniel),
       (daniel)-[:WORKS_FOR]->(eskil)

列表元素访问

下标运算符 [] 可用于访问 LIST 中的特定元素。[0] 指向 LIST 中的第一个元素,[1] 指向第二个,依此类推。[-1] 指向 LIST 中的最后一个元素,[-2] 指向倒数第二个元素,依此类推。

访问 LIST 中的单个元素
WITH [1, 2, 3, 4] AS list
RETURN list[0] AS firstElement,
       list[2] AS thirdElement,
       list[-1] AS finalElement
结果
firstElement thirdElement finalElement

1

3

4

行:1

LIST 中元素的索引可以是参数化的。

参数
{
  "myIndex" : 1
}
使用参数访问 LIST 元素
WITH [1, 2, 3, 4] AS list
RETURN list[$myIndex] AS secondElement
结果
secondElement

2

行:1

访问嵌套 LIST 中的 LIST
WITH [[1, 2], [3, 4], [5, 6]] AS nestedList
RETURN nestedList[1] AS secondList
结果
secondList

[3, 4]

行:1

访问嵌套 LIST 中的特定元素
WITH [[1, 2], [3, 4], [5, 6]] AS nestedList
RETURN nestedList[1] AS secondList,
       nestedList[1][0] AS firstElementOfSecondList
结果
secondList firstElementOfSecondList

[3, 4]

3

行:1

列表元素访问中的索引可以是任何表达式,包括变量。

使用变量作为索引访问列表元素
WITH [[1, 2], [3, 4], [5, 6]] AS nestedList, 2 AS listIndex
RETURN nestedList[listIndex] AS thirdList,
       nestedList[listIndex][listIndex - 1] AS secondElementOfThirdList
结果
thirdList secondElementOfThirdList

[5, 6]

6

行:1

用于检查 LIST 成员资格的 IN 运算符可以与 [] 结合使用,以测试元素是否存在于嵌套 LIST 中。

检查嵌套 LIST 中的成员资格
WITH [[1, 2, 3], [4, 5, 6]] AS nestedList
RETURN 3 IN nestedList[0] AS elementPresent
结果
elementPresent

TRUE

行:1

尝试引用 LIST 边界之外的元素将返回 null,尝试从空 LIST 中访问元素也是如此。

越界和空 LIST 访问
WITH [1, 2, 3, 4] AS list, [] AS emptyList
RETURN list[5] AS outOfBound, emptyList[0] AS emptyAccess
结果
outOfBound emptyAccess

null

null

行:1

列表切片

如果下标运算符内提供了范围,则可以对 LIST 值进行切片。范围的边界使用两个点 (..) 分隔。这允许提取 LIST 的子集而不是单个元素。列表切片在范围的开头是包含的,但在结尾是排除的(例如 list[start..end] 包含 start,但不包含 end)。

LIST 进行切片操作
WITH [1, 2, 3, 4, 5, 6] AS list
RETURN list[2..4] AS middleElements,
       list[..2] AS noLowerBound,
       list[2..] AS noUpperBound
结果
middleElements noLowerBound noUpperBound

[3, 4]

[1, 2]

[3, 4, 5, 6]

行:1

列表切片中的负索引引用 LIST 末尾的元素;..-1 排除最后一个元素,..-2 排除最后两个元素,依此类推。

负索引和列表切片
WITH [1, 2, 3, 4, 5, 6] AS list
RETURN list[..-1] AS finalElementRemoved,
       list[..-2] AS finalTwoElementsRemoved,
       list[-3..-1] AS removedFirstThreeAndLast
结果
finalElementRemoved finalTwoElementsRemoved removedFirstThreeAndLast

[1, 2, 3, 4, 5]

[1, 2, 3, 4]

[4, 5]

行:1

当切片嵌套 LIST 值时,指定切片层级非常重要。以下示例切片外部的 LIST 并返回前两个嵌套的 LIST 值。

切片外部 LIST
WITH [[1, 2, 3], [4, 5, 6], [7, 8, 9]] AS nestedList
RETURN nestedList[0..2] AS slicedNestedList
结果
slicedNestedList

[[1, 2, 3], [4, 5, 6]]

行:1

切片内部 LIST 值需要两个 [] 运算符;第一个 [] 用于访问外部 LIST 的元素,第二个用于切片或访问内部 LIST 的元素。

切片内部 LIST
WITH [[1, 2, 3], [4, 5, 6], [7, 8, 9]] AS nestedList
RETURN nestedList[1][0..2] AS slicedInnerList
结果
slicedInnerList

[4, 5]

行:1

访问特定元素或元素范围还可以与 + 运算符结合使用,以创建一个新 LIST,并将值插入到现有 LIST 值的特定部分中。

将元素插入到 LIST 的特定位置
WITH [1, 3, 4] AS list
RETURN list[0] + [2] + list[1..] AS newList
结果
newList

[1, 2, 3, 4]

行:1

列表拼接

Cypher 包含两个列表拼接运算符:||+|| 符合 GQL 标准,而 + 则不符合。

使用 ||+ 进行列表拼接
RETURN [1,2] || [3,4] AS list1,
       [1,2] + [3,4] AS list2
结果
list1 list2

[1, 2, 3, 4]

[1, 2, 3, 4]

行:1

拼接两个 LIST 属性
MATCH (cecil:Person {name: 'Cecil'}), (cecilia:Person {name: 'Cecilia'})
RETURN cecil.skills || cecilia.skills AS combinedSkills
结果
combinedSkills

["Java", "Python", "JavaScript", "TypeScript"]

行:1

如果 null 是拼接 LIST 的一部分,则 null 将成为新 LIST 的一部分。

拼接包含 nullLIST
RETURN [1, 2] || [3, null] AS listWithNull
结果
listWithNull

[1, 2, 3, null]

行:1

有关在拼接 LIST 值时移除 null 值的信息,请参阅 列表推导

向列表中添加元素

+ 运算符可以将元素添加到 LIST 值的开头或结尾。使用 || 运算符无法实现此操作。

LIST 的开头和结尾添加元素
WITH [1, 2, 3, 4] AS list
RETURN 0 + list AS newBeginning,
       list + 5 AS newEnd
结果
newBeginning newEnd

[0, 1, 2, 3, 4]

[1, 2, 3, 4, 5]

行:1

要将 LIST 值插入到嵌套 LIST 中,添加的 LIST 本身必须是嵌套的。如果添加的 LIST 未嵌套,其元素将被视为单个元素;而如果它是嵌套的,它将在嵌套 LIST 中保持 LIST 结构。

LIST 值添加到嵌套 LIST
WITH [[1, 2], [3, 4]] AS nestedList
RETURN nestedList + [5, 6] AS nonNestedAddition,
       nestedList + [[5, 6]] AS nestedAddition
结果
nonNestedAddition nestedAddition

[[1, 2], [3, 4], 5, 6]

[[1, 2], [3, 4], [5, 6]]

行:1

LIST 属性的开头添加元素
MATCH (cecil:Person {name: 'Cecil'})
SET cecil.skills = "Cypher" + cecil.skills
RETURN cecil.skills AS skillsList
结果
skillsList

["Cypher", "Java", "Python"]

行:1

列表推导

列表推导用于通过迭代现有 LIST 值并根据特定条件或操作转换元素来创建新的 LIST 值。此过程有效地将原始 LIST 中的每个元素映射为一个新值。结果是一个由转换后的元素组成的新 LIST

语法
[item IN list [WHERE predicate] | [expression]]

迭代步骤 (item IN list) 确保逐个访问 list 的每个元素,而 expression 可选择性地将转换应用于每个 item,从而创建包含修改后元素的新 LIST 值。

无表达式的列表推导
RETURN [x IN range(0,10) WHERE x % 2 = 0] AS result
结果
结果

[0, 2, 4, 6, 8, 10]

行:1

无过滤的列表推导
RETURN [x IN range(0,5) | x * 10] AS result
结果
结果

[0, 10, 20, 30, 40, 50]

行:1

带表达式和过滤的列表推导
WITH [1, 2, 3, 4, 5] AS list
RETURN [n IN list WHERE n > 2 | n] AS filteredList
结果
filteredList

[3, 4, 5]

行:1

下一个示例展示了如何使用索引通过列表推导来映射 LISTrange() 函数用于生成从 0LIST 最后一个有效索引的索引,然后将每个索引与其对应的 LIST 值组合成一个 STRING 值。结果是一个格式为 'index: value'STRING 值的 LIST

使用索引映射列表元素
WITH [1,2,3,4] AS list
RETURN [listIndex IN range(0, size(list)-1) | toString(listIndex) || ': ' || toString(list[listIndex])] AS mappedListElements
结果
mappedListElements

["0: 1", "1: 2", "2: 3", "3: 4"]

行:1

以下查询遍历每个 Person 节点的 skills 属性,并通过将 STRING " expert" 拼接到 skills 中的每个元素来创建一个新的 LIST

使用列表推导修改 LIST 属性
MATCH (p:Person) WHERE p.skills IS NOT NULL
ORDER BY p.name
RETURN p.name AS name,
      [skill IN p.skills | skill + " expert"] AS modifiedSkills
结果
名称 (name) modifiedSkills

"Alice"

["Java expert", "Python expert"]

"Cecil"

["Cypher expert", "Java expert", "Python expert"]

"Cecilia"

["JavaScript expert", "TypeScript expert"]

"Charlie"

["C++ expert", "Python expert"]

"Daniel"

["Ruby expert", "Go expert"]

"Eskil"

["Java expert", "C++ expert", "Python expert"]

行数: 6

下一个查询使用 collect() 函数将所有 Person 节点收集到一个 LIST 中,并且 WHERE 'Python' IN person.skills 谓词对该列表进行过滤,以仅包含其 skills 属性包含 Python 的节点。

带有 WHERE 谓词的列表推导
MATCH (p:Person)
RETURN [person IN collect(p) WHERE 'Python' IN person.skills | person.name] AS pythonExperts
结果
pythonExperts

["Alice", "Cecil", "Charlie", "Eskil"]

行:1

列表推导可用于在拼接 LIST 值时移除任何未知的 null 值。

在列表拼接期间使用列表推导移除 null
RETURN [x IN ([1, null, 3] || [null, 5, null]) WHERE x IS NOT NULL] AS listWithoutNull
结果
listWithoutNull

[1, 3, 5]

行:1

模式推导

模式推导用于通过匹配图形模式并将条件应用于匹配的元素来创建新的 LIST 值,并返回自定义投影。

语法
[pattern [WHERE predicate] | expression]

以下查询通过使用模式推导将 employees 的名称提取为 LIST,从而检索为 Alice 工作的员工名单。

针对固定长度模式的模式推导
MATCH (alice:Person {name: 'Alice'})
RETURN [(employee:Person)-[:WORKS_FOR]->(alice) | employee.name] AS employees
结果
employees

["Cecil", "Cecilia"]

行:1

模式推导可以包含 WHERE 谓词。

包含 WHERE 谓词的模式推导
MATCH (alice:Person {name: 'Alice'})
RETURN [(employee:Person)-[:WORKS_FOR]->(alice) WHERE employee.age > 30 | employee.name || ', ' || toString(employee.age)] AS employeesAbove30
结果
employeesAbove30

["Cecilia, 31"]

行:1

模式推导也可以匹配 可变长度模式。但是,模式推导不支持 GQL 标准限定符语法

不允许:使用 GQL 限定符语法的可变长度模式推导
MATCH (cecil:Person {name: 'Cecil'})
RETURN [(cecil)-[:WORKS_FOR]->+(superior:Person) | superior.skills] AS superiorsSkills

模式推导仅支持 可变长度关系 语法。以下查询使用模式推导收集 Cecil 上方链中所有上级的技能。reduce() 函数将这些技能拼接到一个单独的 LIST 中,并使用 UNWIND 在返回新 LIST 中的不同技能之前展平此 LIST

允许:使用可变长度关系语法的可变长度模式推导
MATCH (cecil:Person {name: 'Cecil'})
WITH [(cecil)-[:WORKS_FOR*]->(superior:Person) | superior.skills] AS allSuperiorsSkills
WITH reduce(accumulatedSkills = [], superiorSkills IN allSuperiorsSkills | accumulatedSkills || superiorSkills) AS allSkills
UNWIND allSkills AS superiorsSkills
RETURN collect(DISTINCT superiorsSkills) AS distinctSuperiorsSkills
结果
distinctSuperiorsSkills

["Java", "Python", "Ruby", "Go", "C++"]

行:1