我有一个地图列表形式的数据结构:
List< Map<String, List<String>> >
我想使用java 8功能在单个Set
中收集列表的所有元素(地图的值)。
示例:
Input: [ {"a" : ["b", "c", "d"], "b" : ["a", "b"]}, {"c" : ["a", "f"]} ]
Output: ["a", "b", "c", "d", "f"]
感谢。
答案 0 :(得分:12)
您可以使用一系列Stream.map和Stream.flatMap:
List<Map<String, List<String>>> input = ...;
Set<String> output = input.stream() // -> Stream<Map<String, List<String>>>
.map(Map::values) // -> Stream<List<List<String>>>
.flatMap(Collection::stream) // -> Stream<List<String>>
.flatMap(Collection::stream) // -> Stream<String>
.collect(Collectors.toSet()) // -> Set<String>
;
答案 1 :(得分:5)
为此目的使用flatMap
List< Map<String, List<String>> > maps = ...
Set<String> result = maps.stream()
.flatMap(m -> m.values().stream())
.flatMap(List::stream)
.collect(Collectors.toSet());
答案 2 :(得分:4)
.flatMap
based solutions的替代方法是将这些子迭代融合到最终的collect
操作中:
Set<String> output = input.stream()
.collect(HashSet::new, (set,map) -> map.values().forEach(set::addAll), Set::addAll);
答案 3 :(得分:4)
这个问题有很多替代品。以下是一些使用Eclipse Collections容器提供的其他两个答案。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
import re
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
class MyModel(QStandardItemModel):
def __init__(self, parent=None):
super(MyModel, self).__init__(parent)
def data(self, index, role):
symbol = self.symbol_data[index.row()]
if role == Qt.DisplayRole:
return symbol[1]
elif role == Qt.UserRole:
return symbol[0]
def setup(self, data):
self.symbol_data = data
for line, name in data:
item = QStandardItem(name)
self.appendRow(item)
class MyGui(QDialog):
def __init__(self, parent=None):
super(MyGui, self).__init__(parent)
symbols = [(1, 'cb'), (3, 'cd'), (7, 'ca'), (11, 'aa'), (22, 'bd')]
model = MyModel()
model.setup(symbols)
layout = QVBoxLayout(self)
self.line = QLineEdit(self)
layout.addWidget(self.line)
self.setLayout(layout)
completer = CustomQCompleter()
completer.setModel(model)
completer.setCaseSensitivity(Qt.CaseInsensitive)
completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
completer.setWrapAround(False)
self.line.setCompleter(completer)
self.completer = completer
self.completer.highlighted[QModelIndex].connect(self.test)
# QTimer.singleShot(0, self.completer.complete)
self.line.textChanged[QString].connect(self.pop)
def pop(self, *x):
text = x[0]
self.completer.splitPath(text)
QTimer.singleShot(0, self.completer.complete)
self.line.setFocus()
def test(self, index):
print 'row in completion model', index.row()
print 'data:', index.data(Qt.UserRole).toPyObject()
class CustomQCompleter(QCompleter):
def __init__(self, parent=None):
super(CustomQCompleter, self).__init__(parent)
self.local_completion_prefix = ""
self.source_model = None
self.first_down = True
def setModel(self, model):
self.source_model = model
self._proxy = QSortFilterProxyModel(
self, filterCaseSensitivity=Qt.CaseInsensitive)
self._proxy.setSourceModel(model)
super(CustomQCompleter, self).setModel(self._proxy)
def splitPath(self, path):
self.local_completion_prefix = str(path)
self._proxy.setFilterFixedString(path)
return ""
def eventFilter(self, obj, event):
if event.type() == QEvent.KeyPress:
'This is used to mute the connection to clear lineedit'
if event.key() in (Qt.Key_Down, Qt.Key_Up):
curIndex = self.popup().currentIndex()
if event.key() == Qt.Key_Down:
if curIndex.row() == self._proxy.rowCount()-1:
print 'already last row', curIndex.row()
if self._proxy.rowCount() == 1:
pass
else:
return True
else:
if curIndex.row() == 0:
print 'already first row'
return True
if curIndex.row() == 0 and self.first_down:
print 'already row 0 first'
self.popup().setCurrentIndex(curIndex)
self.first_down = False
return True
super(CustomQCompleter, self).eventFilter(obj, event)
return False
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MyGui()
gui.show()
sys.exit(app.exec_())
注意:我是Eclipse Collections的提交者。