Interation and group - dart

I have a class Account that contains a list of Feature :
class Account{
...
<List>Feature features
and a feature is composed of :
class Feature {
String name;
String description;
bool enabled;
String category;
}
What I want to do is to display them and grouping them by their category. Algorithmically speaking, I don't know how to do. How to Iterate in order to group them. This is an exemple of what the result should be : 2 features that have "travel" as category

You can create a map where the key are the category and value are a list of features:
class Feature {
String name;
String description;
bool enabled;
String category;
Feature(this.name, this.category);
String toString() => name;
}
class Account {
List<Feature> features = [];
}
void main() {
Account account = Account();
account.features.add(Feature("a", "test 1"));
account.features.add(Feature("b", "test 1"));
account.features.add(Feature("c", "test 2"));
final map = <String, List<Feature>>{};
for (var feature in account.features) {
map.update(feature.category, (list) => list..add(feature),
ifAbsent: () => [feature]);
}
print(map);
}

Related

Is there a way to have the Combobox render the selected value like the Select in Vaadin Flow?

For example in the Select component the selected value is rendered as shown here. However when it comes to the ComboBox it is not rendered, only on the dropdown as shown here. I need to use the ComboBox because I need the search functionality, that is to have the item selected as they type in the value because there may be a lot of values. Ideally it would be great to merge the Select and ComboBox but barring that I'm wondering if there's a way to render the selected value.
You can't use an arbitrary Renderer, because the text input is, well, a text input. As noted in the comments below the question, what you're really after is an icon in front of the value of the input, and while there's no nice API in ComboBox for this, you can frankenstein together a solution using the prefix slot of the vaadin-text-field input. I've adapted an example using the Cookbook recipe here. Note that there's an enhancement request that would make handling prefix/suffix components in ComboBox easier: https://github.com/vaadin/flow-components/issues/1594
public class AboutView extends Div {
public AboutView() {
ComboBox<Person> comboBox = new ComboBox<>();
comboBox.setItems(getPersons());
// Renderer for the drop down
comboBox.setRenderer(new ComponentRenderer<Div, Person>(person -> {
Div container = new Div();
container.add(person.getIcon().create(), new Span(person.getName()));
return container;
}));
// on value change: either clear the prefix slot or create a new Icon there
comboBox.addValueChangeListener(e -> {
Person p = e.getValue();
if (p == null) {
PrefixUtil.clearSlot(comboBox, "prefix");
return;
}
PrefixUtil.setPrefixComponent(comboBox, p.getIcon().create());
});
comboBox.setItemLabelGenerator(Person::getName);
add(comboBox);
}
public List<Person> getPersons() {
List<Person> persons = new ArrayList<>();
Person person1 = new Person("Foo", VaadinIcon.ARROW_BACKWARD);
Person person2 = new Person("Bar", VaadinIcon.BAR_CHART);
Person person3 = new Person("Baz", VaadinIcon.PUZZLE_PIECE);
persons.add(person1);
persons.add(person2);
persons.add(person3);
return persons;
}
public static class Person {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
public VaadinIcon getIcon() {
return icon;
}
public void setIcon(VaadinIcon icon) {
this.icon = icon;
}
private VaadinIcon icon;
public Person(String name, VaadinIcon icon) {
this.name = name;
this.icon = icon;
}
}
public static class PrefixUtil {
private static Stream<Element> getElementsInSlot(HasElement target,
String slot) {
return target.getElement().getChildren()
.filter(child -> slot.equals(child.getAttribute("slot")));
}
public static void setPrefixComponent(Component target, Component component) {
clearSlot(target, "prefix");
if (component != null) {
component.getElement().setAttribute("slot", "prefix");
target.getElement().appendChild(component.getElement());
}
}
private static void clearSlot(Component target, String slot) {
getElementsInSlot(target, slot).collect(Collectors.toList())
.forEach(target.getElement()::removeChild);
}
private static Component getChildInSlot(HasElement target, String slot) {
Optional<Element> element = getElementsInSlot(target, slot).findFirst();
if (element.isPresent()) {
return element.get().getComponent().get();
}
return null;
}
public static Component getPrefixComponent(Component target) {
return getChildInSlot(target, "prefix");
}
}
}

How to use SpEL to select and return root objects in a collection by evaluating a list of other sub-objects maintained in a field in the root objects

The service I'm working with is running in Java 8. I am using SpEL to filter a generic collection of objects based on an input expression.
I am successfully filtering the collection when the expression evaluates top-level, primitive fields in the RootObject.
The SpEL Collection Selection feature returns a filtered collection of the RootObjects based on an expression for the key, label, and/or type in the RootObject. This case is working fine.
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("collection", collection);
String selectionExpression = "#collection.?[key matches 'foo|foo2|foo3']";
My problem is how to filter the original collection to return a collection of RootObjects based on evaluating fields in the OtherObject which are in the values list in the RootObject?
i.e., return all RootObjects that have a list item in RootObject.values where OtherObject.name == foo or OtherObject.count > 10 or OtherObject.isSelected == true.
The collection objects look something like these:
public class RootObject {
String key;
String label;
String type;
List<OtherObject> values;
public RootObject() {}
public RootObject(String key, String label, String type, List<OtherObject> values) {
this.key = key;
this.label = label;
this.type = type;
this.values = values;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<OtherObject> getValues() {
return values;
}
public void setValues(List<OtherObject> values) {
this.values = values;
}
}
public class OtherObject {
private String name;
private String label;
private Integer count;
private Integer totalCount;
private Boolean isSelected;
public OtherObject() {}
public OtherObject(String name, String label, int count, int totalCount, boolean isSelected) {
this.name = name;
this.label = label;
this.setCount(count);
this.isSelected = isSelected;
this.totalCount = totalCount;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getLabel() {
return this.label;
}
public void setLabel(String label) {
this.label = label;
}
public Integer getCount() {
return this.count;
}
public void setCount(Integer count) {
this.count = count;
}
public Integer getTotalCount() {
return this.totalCount;
}
public void setTotalCount(Integer totalCount) {
this.totalCount = totalCount;
}
public Boolean getIsSelected() {
return this.isSelected;
}
public void setIsSelected(Boolean isSelected) {
this.isSelected = isSelected;
}
}
I don't think you can do it in pure SpEL; you can implement it in Java and register a custom SpEL function.
You're just looking to do two projections. Within the collection of root objects, you want to project to find those root objects where within its set of values, the projection of criteria you want aren't empty.
#collection.?[!(values.?[name == 'foo' or count > 10 or isSelected == true].isEmpty())]
A projection just makes another list, and you can project based on any boolean expression. And inside a projection, you can continue to use SpEL to figure out that boolean expression, including another projection. You just have to keep in mind that the projection returns a list, whereas the projection criteria needs to be a boolean, so you need to actually check the condition that you're looking for (in this case, that the list is not empty).
Here's the test I did to demonstrate to myself that in fact that it was the right syntax and worked correctly:
#Test
public void test() {
final OtherObject otherFooOneNotSelected = new OtherObject("foo", "", 1, 1, false);
final OtherObject otherBarOneNotSelected = new OtherObject("bar", "", 1, 1, false);
final OtherObject otherFooTwelveNotSelected = new OtherObject("foo", "", 12, 12, false);
final OtherObject otherBarTwelveNotSelected = new OtherObject("bar", "", 12, 12, false);
final OtherObject otherFooOneSelected = new OtherObject("foo", "", 1, 1, true);
final OtherObject otherBarOneSelected = new OtherObject("bar", "", 1, 1, true);
final OtherObject otherFooTwelveSelected = new OtherObject("foo", "", 12, 12, true);
final OtherObject otherBarTwelveSelected = new OtherObject("bar", "", 12, 12, true);
final RootObject rootNoValues = new RootObject("noValues", "", "", Collections.<OtherObject>emptyList());
final RootObject rootFooOneNotSelected = new RootObject("rootFooOneNotSelected", "", "", Collections.singletonList(otherFooOneNotSelected));
final RootObject rootBarOneNotSelected = new RootObject("rootBarOneNotSelected", "", "", Collections.singletonList(otherBarOneNotSelected));
final RootObject rootBarTwelveNotSelected = new RootObject("rootBarTwelveNotSelected", "", "", Collections.singletonList(otherBarTwelveNotSelected));
final RootObject rootAllValues = new RootObject("allValues", "", "", Arrays.asList(
otherFooOneNotSelected,
otherBarOneNotSelected,
otherFooTwelveNotSelected,
otherBarTwelveNotSelected,
otherFooOneSelected,
otherBarOneSelected,
otherFooTwelveSelected,
otherBarTwelveSelected));
final Collection<RootObject> collection = Arrays.asList(rootNoValues, rootFooOneNotSelected, rootBarOneNotSelected, rootBarTwelveNotSelected, rootAllValues);
final ExpressionParser parser = new SpelExpressionParser();
final StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("collection", collection);
final String selectionExpression = "#collection.?[!(values.?[name == 'foo' or count > 10 or isSelected == true].isEmpty())]";
final List<?> result = (List<?>) parser.parseExpression(selectionExpression).getValue(context);
assertEquals("Result", Arrays.asList(rootFooOneNotSelected, rootBarTwelveNotSelected, rootAllValues), result);
}

How to read properties of node in neo4j?

I am quite new to neo4j, and constructing db which consists of >10M nodes. During query operations I want to find a node by using two properties of it. For example: node - name: xxx surname: yyy id:1 during query operation I need to get node id which name: xxx, surname: yyy. How is it possible with java query (not cypher)? And there will be more than one entry with given properties.
Here is an example how to find ids:
GraphDatabaseService database;
Label label = DynamicLabel.label("your_label_name");
String propertyId = "id";
String propertyName = "name";
String propertySurname = "surname";
public Set<Node> getIdsForPeople(Set<Person> people) {
Set<String> ids = new HashSet<>();
try(Transaction tx = database.beginTx()) {
for (Person person in people) {
Node node = database.findNode(label, propertyName, person.getName());
if (node.hasProperty(propertySurname)) {
if (node.getProperty(propertySurname) == person.getSurname()) {
String id = node.getProperty(propertyId).toString();
ids.add(id);
}
}
}
tx.success();
}
return ids;
}
Person holder
public class Person {
private final String name;
private final String surname;
public Person(String name, String surname) {
this.name = name;
this.surname = surname;
}
public String getName() { return name; }
public String getSurname() { return surname; }
}
example
Set<Person> people = new HashSet<Person>(){{
add(new Person("xxx1", "yyy1"));
add(new Person("xxx2", "yyy2"));
add(new Person("xxx3", "yyy3");
add(new Person("xxx4", "yyy4");
}};
Set<String> ids = getIdsForPeople(people);

SDN 4 doesn't create relationship with properties

I am new to Neo4J. I have built a project that uses spring-data-neo4j (4.0.0.BUILD-SNAPSHOT - version), spring-boot (1.2.3.RELEASE - version) and succeeded to create node entities, add properties to node entities and add relationships. It works fine. Now I want to create properties for the relationships. I have used sdn4 university as a reference, here is the link https://github.com/neo4j-examples/sdn4-university .
I want to create a property called "challengedBy" for relationship PLAY_MATCH (Start node is Match and end node is Player). You can have a look on below class.
#RelationshipEntity(type = "PLAY_MATCH")
public class PlayMatch extends Entity {
//Entity is a class with the id property for the node / relationship
#Property
private String challengedBy;
#StartNode
private Match match;
#EndNode
private Player player1;
}
I have created a controller in the project /api/playmatch to create only the relationship between match and a player. So when I pass the values for an existing match node and a player node, the relationship is not created at all.
Any help will be appreciated..
PlayMatch code is
#RelationshipEntity(type = "PLAY_MATCH")
public class PlayMatch extends Entity{
#Property
private String challengedBy;
#StartNode
private Match match;
#EndNode
private Player player1;
public PlayMatch() {
}
public PlayMatch(String challengedBy, Match match,
Player player1) {
super();
this.challengedBy = challengedBy;
this.match = match;
this.player1 = player1;
}
// after this i have getters & setters and toString method for above fields.
}
Match code is
#NodeEntity(label = "Match")
public class Match extends Entity {
private String createdBy;
private Long createdTime;
private String status;
private int noOfGames;
private int noOfPoints;
private String type;
private Long date;
#Relationship(type="PLAY_MATCH",direction= Relationship.UNDIRECTED)
private PlayMatch playMatch;
public Match() {
}
public Match(String createdBy, Long createdTime, String status,
int noOfGames, int noOfPoints, String type, Long date) {
super();
this.createdBy = createdBy;
this.createdTime = createdTime;
this.status = status;
this.noOfGames = noOfGames;
this.noOfPoints = noOfPoints;
this.type = type;
this.date = date;
}
public PlayMatch getPlayMatch() {
return playMatch;
}
public void setPlayMatch(PlayMatch playMatch) {
this.playMatch = playMatch;
}
// after this i have getters & setters and toString method for above fields.
}
Player code is
#NodeEntity(label = "Player")
public class Player extends Entity {
private String address;
private String preferredSport;
private float height;
private float weight;
private String phone;
private String photo;
#Relationship(type="PLAY_MATCH")
private PlayMatch playMatch;
public PlayMatch getPlayMatch() {
return playMatch;
}
public void setPlayMatch(PlayMatch playMatch) {
this.playMatch = playMatch;
}
public Player() {
}
public Player(String address, String preferredSport, float height,
float weight, String phone, String photo) {
super();
this.address = address;
this.preferredSport = preferredSport;
this.height = height;
this.weight = weight;
this.phone = phone;
this.photo = photo;
}
// after this i have getters & setters and toString method for above fields.
}
I think you have playmatch relationship within the player end node as well. If you comment the following code in the player node. It should work. I have also attached a json sample to pass from the UI in the match URL (/api/match) instead of (/api/playmatch)
#Relationship(type="PLAY_MATCH")
private PlayMatch playMatch;
public PlayMatch getPlayMatch() {
return playMatch;
}
public void setPlayMatch(PlayMatch playMatch) {
this.playMatch = playMatch;
}
Sample JSON
{
"type": "typename",
"status": "statusname",
"createdTime": 1435928223021,
"noOfGames": 5,
"noOfPoints": 19,
"playMatch": {"challengedBy" : "John", "player1" : {"id":732}, "match":{"type": "typename",
"status": "statusname",
"createdTime": 1435928223021,
"noOfGames": 5,
"noOfPoints": 19}}
}
this should create a new match and a new relationship with property challengedBy to an existing player node with id 732.
check it out and let me know if this works.

Creating a list from ENUM into Model

I got the following model piece of code:
public enum EnumTest
{
[Description ("Enum Text 1")]
Value_1 = 1,
[Description ("Enum Text 2")]
Value_2 = 2,
}
public List<Fields> listFields = new List<Fields>();
public class Fields
{
public int Code { get; set;}
public string Description { get; set;}
}
I got an Enum and I would like to fill my variable CODE with enum value and the variable Description with the same enum description. I looked up a long time and failed to initialize my "ListFields" into its constructor with the enum VALUE/DESCRIPTION.
I already got the enum and the method to get its description.. I found it usefull, so I'll leave it here, maybe it can be useful for someone..
public static string GetDescription(this Enum value)
{
return (from m in value.GetType().GetMember(value.ToString())
let attr =(DescriptionAttribute)m.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault()
select attr == null ? value.ToString() : attr.Description).FirstOrDefault();
}
To use this you just need to do something like this:
String xx = Enum.EnumName.GetDescription();
You have to use reflection.
public static Fields[] GetEnumFields(Type enumType)
{
if (enumType == null)
throw new ArgumentNullException("enumType");
if (!enumType.IsEnum)
throw new ArgumentException("Not an enum");
FieldInfo[] fieldInfos = enumType.GetFields(BindingFlags.Static | BindingFlags.Public);
Fields[] result = new Fields[fieldInfos.Length];
for (int i = 0; i < fieldInfos.Length; ++i)
{
FieldInfo field = fieldInfos[i];
int value = (int)field.GetValue(null);
DescriptionAttribute attrib = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
string desc = attrib != null ? attrib.Description : field.Name;
result[i] = new Fields(value, desc);
}
return result;
}
public class Fields
{
private int value;
private string description;
public int Value
{
get { return this.value; }
}
public string Description
{
get { return this.description; }
}
public Fields(int value, string description)
{
this.value = value;
this.description = description;
}
}
To use it is quite simple:
enum test
{
[Description("hello!")]
ciao,
www
}
static void Main(string[] args)
{
foreach (Fields f in GetEnumFields(typeof(test)))
{
Console.WriteLine(f.Description);
}
}
In my implementation when a descriptionattribute is not found, field name is used.
We must also say that reflection can be slow and rebuilding the entire array when you need it is a waste of time, if you need it often.
You can store the array somewhere so you can compute it only once and keep it cached.
This of course and as I said, makes sense only if you need this readonly list very often.

Resources