I'm having a Flux that emits items:
data class Item(
val isEgg: Boolean,
val isBasket: Boolean
)
Consider 2 'baskets' and 4 'eggs' emissions. I would like to merge those emissions into two: each containing one 'basket' and 4 'eggs':
Is someone aware of such transformation? Flux is finite and should not exceed 1K items.
EDIT:
What I achieved so far - I grouped emissions into GroupedFlux. Now I would need to combine GroupedFlux containing Basket1, Basket2 with with second containing 'Eggs' in order to produce two baskets with "duplicated" eggs in each one.
val flux = Flux.just("Egg1", "Egg2", "Basket1", "Egg3", "Egg4", "Basket2")
val block = flux.groupBy {
it.startsWith("Egg")
}
Desired Flux: Flux.just("Basket1(Egg1,Egg2, Egg3, Egg4)","Basket2(Egg1,Egg2, Egg3, Egg4)")
You can achieve this result with flatMap and reduce:
void combine() {
Flux<String> flux =
Flux.just("Egg1", "Egg2", "Basket1", "Egg3", "Egg4", "Basket2");
Flux<String> eggs = flux.filter(str -> str.startsWith("Egg"));
Flux<String> basketNames = flux.filter(str -> str.startsWith("Basket"));
basketNames.flatMap(basketName -> eggs.reduce(
new Basket(basketName),
(basket, egg) -> {
basket.add(egg);
return basket;
})
);
}
class Basket {
private final String name;
private final List<String> eggs;
Basket(final String name) {
this.name = name;
this.eggs = new ArrayList<>();
}
public void add(String egg) {
eggs.add(egg);
}
}
Your question is not very clear. I would say that checkout the merge() and concat() operators. That should help.
Edit:
Based on the additional details provided, the question is now clear.
One possible solution is given below:
#Test
public void testBasket() {
Egg eggA = new Egg("A");
Egg eggB = new Egg("B");
Egg eggC = new Egg("C");
Egg eggD = new Egg("D");
Basket basket1 = new Basket("basket1");
Basket basket2 = new Basket("basket2");
Sorter sorter = new Sorter();
Sorter updatedSorter = Flux .just((Item) basket1, (Item) basket2, (Item) eggA, (Item) eggB, (Item) eggC,
(Item) eggD)
.map(sorter::add)
.blockLast();
updatedSorter.process();
Flux<Basket> fluxBasket = Flux.fromStream(sorter.baskets.stream());
fluxBasket.subscribe(d -> System.out.println("data:" + d));
}
class Sorter {
List<Egg> eggs = new ArrayList<Egg>();
List<Basket> baskets = new ArrayList<Basket>();
public Sorter add(Item item) {
if (item.isBasket)
baskets.add((Basket) item);
else
eggs.add((Egg) item);
return this;
}
public Sorter process() {
System.out.println("---- Processing Eggs ----");
for (Basket basket : baskets) {
basket.addEggs(eggs);
}
System.out.println("---- Processing Done ----");
System.out.println(this.toString());
return this;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("(");
for (Basket basket : baskets) {
sb.append(basket.toString() + ",");
}
sb.deleteCharAt(sb.length() - 1);
sb.append(")");
return sb.toString();
}
}
class Item {
boolean isEgg;
boolean isBasket;
}
class Basket extends Item {
public Basket(String name) {
this.name = name;
isBasket = true;
}
String name;
List<Egg> eggs = new ArrayList<Egg>();
public void addEggs(List<Egg> eggs) {
this.eggs = eggs;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(this.name);
sb.append("(");
for (Egg egg : eggs) {
sb.append(egg.toString() + ",");
}
sb.deleteCharAt(sb.length() - 1);
sb.append(")");
return sb.toString();
}
}
class Egg extends Item {
public Egg(String name) {
this.name = name;
isEgg = true;
}
String name;
public String toString() {
return this.name;
}
}
Output:
---- Processing Eggs ----
---- Processing Done ----
(basket1(A,B,C,D),basket2(A,B,C,D))
data:basket1(A,B,C,D)
data:basket2(A,B,C,D)
Edit2:
Another solution, without a blocking call:
#Test
public void testBasket() {
Egg eggA = new Egg("A");
Egg eggB = new Egg("B");
Egg eggC = new Egg("C");
Egg eggD = new Egg("D");
Basket basket1 = new Basket("basket1");
Basket basket2 = new Basket("basket2");
Sorter sorter = new Sorter();
Mono<Sorter> bucketsMono = Flux .just((Item) basket1, (Item) basket2, (Item) eggA, (Item) eggB, (Item) eggC,
(Item) eggD)
.map(sorter::add)
.reduce((sorter1, sorter2) -> sorter.process());
bucketsMono.subscribe(d -> System.out.println("data:" + d));
}
Output:
(basket1),basket2))
---- Processing Eggs ----
---- Processing Done ----
(basket1(A),basket2(A))
---- Processing Eggs ----
---- Processing Done ----
(basket1(A,B),basket2(A,B))
---- Processing Eggs ----
---- Processing Done ----
(basket1(A,B,C),basket2(A,B,C))
---- Processing Eggs ----
---- Processing Done ----
(basket1(A,B,C,D),basket2(A,B,C,D))
data:(basket1(A,B,C,D),basket2(A,B,C,D))
Related
I have problem with select 2. It dont show all Items, but only subset. I dont see on Select2Choice any method, which show all items. Can someone give me a poit how to show whole items.
Here is code:
originStationDropDown = new Select2Choice<>("originDgfStation", new PropertyModel<Station>(this, "originStation") , new StationsProvider(originCountryDD, productDD));
ComponentHelper.addLabelAndComponent(originStationDropDown, this, "originStation.label", ComponentOptions.REQUIRED);
private class StationsProvider extends ChoiceProvider<Station> {
private Select2Choice<Country> countryDD;
private DropDownChoice<Product> productDD;
public StationsProvider(Select2Choice<Country> countryDD, DropDownChoice<Product> productDD) {
this.countryDD = countryDD;
this.productDD = productDD;
}
#Override
public void query(String codeNameFragment, int i, Response<Station> response) {
if(codeNameFragment == null || "".equals(codeNameFragment)) {
List<Station> stations = stationDao.findByCountryAndProduct(countryDD.getModel().getObject(), productDD.getModel().getObject(), "code");
for(Station station : stations) {
response.add(station);
}
} else {
response.addAll(stationDao.findByCountryAndProductAndFragment(countryDD.getModel().getObject(), productDD.getModel().getObject(), codeNameFragment));
}
System.out.println(response.size());
}
#Override
public void toJson(Station station, JSONWriter jsonWriter) throws JSONException {
jsonWriter.key("id").value(station.getId()).key("text").value(station.getNameWithCode());
}
#Override
public Collection<Station> toChoices(Collection<String> collection) {
List<Station> stations = new ArrayList<>();
List<Station> stationList = stationDao.findAll();
for(String id : collection) {
for(Station station : stationList) {
if(station.getId().equals(Long.valueOf(id))) {
stations.add(station);
}
}
}
return stations;
}
}
You don't explain which items are shown and which are not.
I will guess that only the first N items are always shown. The second parameter of #query() method is int page (named i in your code). This parameter should be used to paginate the results. I.e. you should not always return 10000 items and let the JavaScript to deal with them but you have to return 0-20, 21-40, 41-60, etc.
So I am trying to visualize a curricilum as a table. It should look like this:
As you can see there are custom cells (+) which are not a lesson. They are buttons.
I have two classes:
public class Lesson {
private Room schoolRoom;
private Room teachingRoom;
private TeacherSpecialization teachingInfo;
private WeekDay weekDay;
private int schoolHour;
}
and
public class ClassHour {
Lesson[] dayLessons = new Lesson[18];
private int hour;
public ClassHour(int hour) {
this.hour = hour;
}
}
Using this code I convert my Lesson Object to ClassHour objects, because I use the ClassHour Object to save the lessons in the table:
public ObservableList<ClassHour> convertToClassHour(List<Lesson> lessons) {
ObservableList<ClassHour> classHours = FXCollections.observableArrayList();
// Converting Lessons to ClassHour objects.
lessons.forEach(lesson -> {
ClassHour classHour = classHours.stream().filter(ch -> ch.getHour() == lesson.getSchoolHour()).findFirst().orElse(null);
if (classHour == null) {
classHour = new ClassHour(lesson.getSchoolHour());
classHours.add(classHour);
}
classHour.getDayLessons()[lesson.getWeekDay().ordinal()] = lesson;
});
return classHours;
}
And the last step is to show the data in the table:
private void showLessons(String roomNr) throws Exception {
try {
// lessons.addListener((ListChangeListener) e -> repopulate(lessons, classHours));
ArrayList<Lesson> allLessonsByRoomNr = db.getAllLessonsByRoomNr(roomNr);
ObservableList<ClassHour> classHours = db.convertToClassHour(allLessonsByRoomNr);
for (int i = 0; i < 5; i++) {
int day = i;
TableColumn<ClassHour, Lesson> dayColumn = new TableColumn<>(WeekDay.values()[i].name());
dayColumn.setSortable(false);
dayColumn.setCellValueFactory(param -> new SimpleObjectProperty(param.getValue().getDayLessons()[day]));
dayColumn.setCellFactory((TableColumn<ClassHour, Lesson> param) -> new TableCell<ClassHour, Lesson>() {
#Override
protected void updateItem(Lesson item, boolean empty) {
super.updateItem(item, empty);
setText(null);
setGraphic(null);
if (!empty) {
if (item != null) {
setText(item.toString());
} else {
Button btn = new Button("+ ADD");
btn.setOnAction(e -> {
tableLessons.getSelectionModel().select((ClassHour) getTableRow().getItem());
showAdd(day, ((ClassHour) getTableRow().getItem()).getHour(), btn);
});
setGraphic(new StackPane(btn));
}
}
}
});
tableLessons.getColumns().addAll(dayColumn);
}
tableLessons.setItems(classHours);
} catch (Exception ex) {
showResultDialog("An error has occured:", ex.getMessage());
}
}
The problem I am struggling are the custom cells (+ buttons). For some reason I can't draw them between two lessons. In the case below there should be 5 cells/rows between classhour 10 and 16 (monday).
Note that your convertToClassHour creates a ClassHour instance if and only if there is a Lesson and if the Lessons are not ordered by hour, the order of ClassHours in the output is wrong.
Unless you've got a predetermined set of hours, you need to find the min and max hours to fix your issue:
public ObservableList<ClassHour> convertToClassHour(List<Lesson> lessons) {
ObservableList<ClassHour> classHours = FXCollections.observableArrayList();
if (!lessons.isEmpty()) {
// find required hour range
int minHour = lessons.mapToInt(Lesson::getSchoolHour).min().getAsInt();
int maxHour = lessons.mapToInt(Lesson::getSchoolHour).max().getAsInt();
// create ClassHours for range
for (int i = minHour; i <= maxHour; i++) {
classHours.add(new ClassHour(i));
}
// fill classHours with lessons
for (Lesson lesson : lessons) {
classHours.get(lesson.getSchoolHour() - minHour).getDayLessons()[lesson.getWeekDay().ordinal()] = lesson;
}
}
return classHours;
}
I would like to know how I can return the node names instead of the node IDs in the Java console.
The following output is shown in the console:
The desired output should look like:
Just without all the information but only with the Node names (which equal Airportnames).
My Java code looks like the following:
package com.routesNeo4j;
import org.neo4j.driver.v1.*;
import java.util.ArrayList;
import java.util.List;
/**
* Created by e on 11.06.17.
*/
public class Neo4JRouting implements AutoCloseable, Neo4J_Connector {
static Driver driver;
public Neo4JRouting(String startAirport, String destinationAirport, StatementResult shortestPath) {
driver = GraphDatabase.driver("bolt://ec2-13-58-101-13.us-east-2.compute.amazonaws.com:7687",
AuthTokens.basic("neo4j", "Einloggen_123"));
try(Session session = driver.session()) {
shortestPath = session.run("MATCH (a:" + startAirport.toLowerCase() + "), (b:" + destinationAirport.toLowerCase()
+ "), p = allShortestPaths((a)-[r*1..4]-(b)) UNWIND rels(p) AS rel RETURN nodes(p), sum(rel.weight) " +
"AS weight ORDER BY sum(rel.weight)");
List<Record> storeList = storeList(shortestPath);
while (shortestPath.hasNext()) {
System.out.println(shortestPath.next().toString());
}
System.out.println(storeList);
} catch (Exception e) {
e.printStackTrace();
}
}
public List<Record> storeList(StatementResult statementResult) {
List<Record> list = new ArrayList<>();
while (statementResult.hasNext()) {
list.add(statementResult.next());
}
return list;
}
#Override
public Driver runDriver(String user, AuthToken basicAuthToken) throws Exception {
return null;
}
#Override
public void close() throws Exception {
}
}
I am looking forward to your answers. Many thanks!
Every row you are returning contains a list of nodes and a weight. That's what you ask in your query and that's what you get. So you have to "unpack" that result into the format that you desire.
Couple of code-snippets to show what I mean :
StatementResult vResult = vSession.run(aCypher);
while (vResult.hasNext()) {
Record vRecord = vResult.next();
vMutator.pushNode("row");
for (Pair <String, Value> vListEntry : vRecord.fields()) {
process_listentry(vSession, vMutator, vListEntry.key(), vListEntry.value());
}
vMutator.popNode(); // row
}
and then in process_listentry :
private void process_listentry(Session vSession, IHDSMutator vMutator, String vKey, Value vValue) {
...
else if (vValue.type().equals(vSession.typeSystem().NODE())){
vMutator.pushNode(vKey);
vMutator.addNode("_id", Long.toString(vValue.asNode().id()));
for (String lLabel : vValue.asNode().labels()) {
vMutator.addNode("_label", lLabel);
}
for (String lKey : vValue.asNode().keys()) {
Value lValue = vValue.asNode().get(lKey);
process_listentry(vSession, vMutator, lKey, lValue);
}
vMutator.popNode();
}
...
but it does depend on what you ask in the query and thus have to unpack ...
Hope this helps,
Tom
public class Expandablelistview extends MainScreen {
public Expandablelistview() {
// A separator field between each type of control\
// setTitle("Tree Field Demo");
String parentfield1 = new String("Demo1");
String parentfield2 = new String("Demo2");
String childfield1 = new String("Demo3");
String childfield2 = new String("Demo4");
String parentfield3 = new String("Demo5");
String parentfield4 = new String("Demo6");
String childfield3 = new String("Demo7");
String childfield4 = new String("Demo8");
String childfield5 = new String("Demo9");
String childfield6 = new String("Demo10");
String parentfield5 = new String("Demo11");
String childfield7 = new String("Demo12");
String childfield8 = new String("Demo13");
TreeCallback myCallback = new TreeCallback();
final TreeField myTree = new TreeField(myCallback, Field.FOCUSABLE);
myTree.setDefaultExpanded(false);
int node12 = myTree.addChildNode(0, parentfield5);
int node13 = myTree.addChildNode(node12, childfield7);
int node14 = myTree.addChildNode(node12, childfield8);
// int node7 = myTree.addChildNode(0, parentfield5);
int node6 = myTree.addChildNode(0, parentfield4);
int node11 = myTree.addChildNode(node6, childfield6);
int node10 = myTree.addChildNode(node6, childfield5);
int node8 = myTree.addChildNode(node6, childfield3);
int node9 = myTree.addChildNode(node6, childfield4);
int node5 = myTree.addChildNode(0, parentfield3);
int node2 = myTree.addChildNode(0, parentfield2);
int node3 = myTree.addChildNode(node2, childfield1);
int node4 = myTree.addChildNode(node2, childfield2);
int node1 = myTree.addChildNode(0, parentfield1);
add(myTree);
// myTree.setChangeListener(new myTreeChangeListener());
// HERE I TRIED FOR ITEM CLICK
FieldChangeListener fdbtncalculate = new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
// TODO Auto-generated method stub
int a = myTree.getNodeCount();
System.out.print("mytree" + a);
if (a == 0) {
Dialog.alert("data");
} else if (a == 1) {
Dialog.alert("data");
}
}
};
myTree.setChangeListener(fdbtncalculate);
}
private class TreeCallback implements TreeFieldCallback {
public void drawTreeItem(TreeField _tree, Graphics g, int node, int y,
int width, int indent) {
String text = (String) _tree.getCookie(node);
g.drawText(text, indent, y);
}
}
}
i want to know what i am doing wrong? i want to open my class file on click of parent and child item of treeview for that i used field listener
Instead of using a FieldChangeListener, try this code, which overrides navigationClick():
TreeCallback myCallback = new TreeCallback();
TreeField myTree = new TreeField(myCallback, Field.FOCUSABLE) {
protected boolean navigationClick(int status, int time) {
// We'll only override unvarnished navigation click behavior
if ((status & KeypadListener.STATUS_ALT) == 0 &&
(status & KeypadListener.STATUS_SHIFT) == 0)
{
final int node = getCurrentNode();
if (getFirstChild(node) == -1) {
// Click is on a leaf node.
Dialog.alert("clicked leaf node " + getCookie(node));
return true;
} else {
// Node is a parent node
setExpanded(node, !getExpanded(node));
Dialog.alert("clicked parent node " + getCookie(node));
return true;
}
}
return super.navigationClick(status, time);
}
};
I'm not sure what you mean by "open new class file", but whatever you want to do after the user clicks a part of the tree, you would do it where I have the Dialog.alert() code above.
I have a style requirement that my data grid show the horizontal grid lines every 3 rows...
Something like this:
-----------------------------------
one | two | three | four |
five | six | seven | eight |
nine | ten | eleven | twelve |
-----------------------------------
aaa | bbb | ccc | ddd |
eee | fff | ggg | hhh |
iii | jjj | kkk | lll |
-----------------------------------
mmm | nnn | ooo | ppp |
etc..
Does anyone know of an easy way of achieving this? I was considering updating the row style to include a border, and set the bottom border thickness to 1 every (x mod n) times, but this seems wrong.
There must be a better way?
So, after hacking away at it, I figured out a way. It is pretty nasty, but it works.
If I were in WPF, I would use the AlternationIndex and set a style trigger for index 0,1,2 and set the border thickness of index 2 to have a bottom index.
In Silverlight, we don't have AlternationIndex OR style triggers. So, I had to hack. I wrapped the code into a behavior, so my XAML is pretty clean:
Controls:DataGrid DataGridLines:HorizontalGridLineModulus.Index="3" ... />
The code to support it looks like this:
public static class HorizontalGridLineModulus
{
private static readonly DependencyProperty HorizontalGridLineModulusBehaviorProperty =
DependencyProperty.RegisterAttached(
"HorizontalGridLineModulusBehavior",
typeof (HorizontalGridLineModulusBehavior),
typeof (DataGrid),
null);
public static readonly DependencyProperty IndexProperty =
DependencyProperty.RegisterAttached(
"Index",
typeof (int),
typeof (HorizontalGridLineModulus),
new PropertyMetadata(1, IndexChanged)
);
public static int GetIndex(DependencyObject dependencyObject)
{
return (int)dependencyObject.GetValue(IndexProperty);
}
public static void SetIndex(DependencyObject dependencyObject, int value)
{
dependencyObject.SetValue(IndexProperty, value);
}
private static void IndexChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var behavior = dependencyObject.GetValue(HorizontalGridLineModulusBehaviorProperty) as HorizontalGridLineModulusBehavior;
if (behavior == null)
{
behavior = new HorizontalGridLineModulusBehavior(dependencyObject as DataGrid, (int)e.NewValue);
dependencyObject.SetValue(HorizontalGridLineModulusBehaviorProperty, behavior);
}
}
}
public class HorizontalGridLineModulusBehavior
{
private readonly DataGrid _grid;
private readonly int _modulus;
public HorizontalGridLineModulusBehavior(DataGrid grid, int modulus)
{
if(grid == null)
throw new ArgumentException("grid");
_grid = grid;
_modulus = modulus;
_grid.LayoutUpdated += GridLayoutUpdated;
}
private void GridLayoutUpdated(object sender, EventArgs e)
{
DrawBorders();
}
private void DrawBorders()
{
var presenter = _grid.Descendants<DataGridRowsPresenter>().FirstOrDefault();
if(presenter == null) return;
var orderedRows = presenter.Children.OrderBy(child => RowIndex(child));
int count = 0;
foreach (var row in orderedRows)
{
count++;
var gridLine = row.Descendants<Rectangle>().Where(x => x.Name == "BottomGridLine").FirstOrDefault();
if(gridLine != null)
gridLine.Visibility = count % _modulus != 0 ? Visibility.Collapsed : Visibility.Visible;
}
}
private static int RowIndex(UIElement element)
{
var row = element as DataGridRow;
return row == null ? 0 : row.GetIndex();
}
}
That code makes use of a few extension methods, defined here:
public static class DependencyObjectExtensions
{
public static IEnumerable<DependencyObject> Children(this DependencyObject element)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
yield return VisualTreeHelper.GetChild(element, i);
}
public static IEnumerable<T> Children<T>(this DependencyObject element) where T : DependencyObject
{
return element.Children().Filter<T>();
}
public static IEnumerable<DependencyObject> Descendants(this DependencyObject element)
{
foreach (var child in element.Children())
{
yield return child;
foreach (var descendent in child.Descendants())
yield return descendent;
}
}
public static IEnumerable<T> Descendants<T>(this DependencyObject element) where T : DependencyObject
{
return element.Descendants().Filter<T>();
}
public static IEnumerable<T> Filter<T>(this IEnumerable list) where T : class
{
foreach (var item in list)
{
if (item is T)
yield return (T)item;
}
}
}