I got a task that migrate code from C# to java 8.
And I have a problem with the C# codes below.
List<Log> lst = LogRepository.GetLogs(DateTime.Now.AddDays(-2), DateTime.Now);
return lst
.GroupBy(x => new { x.Title, x.ID })
.Select(x => x.OrderByDescending(y => y.DataChangeTime).FirstOrDefault())
.ToList();
Yes ,the method GroupBy is easy,I know what is it doing.
But ,I can't figure out what is this series methods doing and what results will it return ?
Finally,can anyone give me a java version solution ?
The C#-code is already explained by #Rango. Assuming the following design for the Log-class in C#
class Log
{
public String title;
public String ID;
public DateTime dataChangeTime;
public String whatever;
...
}
and an analogous Java-class (with e.g. LocalDateTime instead of DateTime), a Java-expression providing the same result is:
Comparator<Log> comparator = (Log l1, Log l2) -> l2.dataChangeTime.compareTo(l1.dataChangeTime); // sort descending
List<Log> resultantList = initialList.stream()
.collect(Collectors.groupingBy(l -> l.title + l.ID)).values().stream() // group according to title and id
.map(logs -> logs.stream().sorted(comparator).findFirst().get()) // sort and take the first
.collect(Collectors.toList()); // create the list
The expression groups all Log-objects together having the same title and ID, i.e. the same value of l.title + l.ID. If the grouping-condition is more complex then it might make more sense to define a class which represents the grouping, e.g.
class LogGroup {
private String Title;
private String ID;
public LogGroup(String Title, String ID) {
this.Title = Title;
this.ID = ID;
}
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof LogGroup)) {
return false;
}
LogGroup logGroup = (LogGroup) o;
return Objects.equals(Title, logGroup.Title) &&
Objects.equals(ID, logGroup.ID);
}
#Override
public int hashCode() {
return Objects.hash(Title, ID);
}
}
It's crucial that the class implements both, the equals- and the hashCode-method (i.e the implementation of the equals-method alone is not enough).
Using that class the Java-expression becomes:
Comparator<Log> comparator = (Log l1, Log l2) -> l2.dataChangeTime.compareTo(l1.dataChangeTime);
List<Log> resultantList = initialList.stream()
.collect(Collectors.groupingBy(l -> new LogGroup(l.title, l.ID))).values().stream()
.map(logs -> logs.stream().sorted(comparator).findFirst().get())
.collect(Collectors.toList());
A list like
private static List<Log> getInitialList() {
List<Log> initialList = new ArrayList<>();
initialList.add(new Log("Title 6", "ID 6", LocalDateTime.of(2017, 1, 18, 23, 15, 12), "A"));
initialList.add(new Log("Title 3", "ID 3", LocalDateTime.of(2005, 4, 20, 16, 10, 10), "B"));
initialList.add(new Log("Title 1", "ID 1", LocalDateTime.of(2010, 10, 25, 3, 5, 2), "C"));
initialList.add(new Log("Title 2", "ID 2", LocalDateTime.of(2018, 2, 18, 21, 13, 32), "D"));
initialList.add(new Log("Title 3", "ID 3", LocalDateTime.of(2016, 5, 16, 15, 23, 15), "E"));
initialList.add(new Log("Title 1", "ID 1", LocalDateTime.of(2012, 2, 8, 14, 46, 28), "F"));
initialList.add(new Log("Title 6", "ID 6", LocalDateTime.of(1996, 1, 28, 22, 26, 34), "G"));
initialList.add(new Log("Title 3", "ID 3", LocalDateTime.of(2007, 4, 15, 2, 5, 55), "H"));
initialList.add(new Log("Title 6", "ID 3", LocalDateTime.of(2018, 1, 15, 20, 15, 10), "I"));
return initialList;
}
is processed by both expressions as follows
Title 1 ID 1 2012-02-08 14:46:28 F
Title 3 ID 3 2016-05-16 15:23:15 E
Title 2 ID 2 2018-02-18 21:13:32 D
Title 6 ID 6 2017-01-18 23:15:12 A
Title 6 ID 3 2018-01-15 20:15:10 I
The resultant list itself isn't sorted (which would be easy to implement with Collections.sort(...)), but that applies also to the C#-output.
Related
I have a list of products and a list of types, but to know what type the product belongs to I need to rely on the ID in the type list, so I need to convert it to a new NewProducts list and its type is a String, not an Integer.
data class Product(val id:String,val name:String,val price:Float,val type:Int)
data class Type(val id:Int,val name:String)
corresponding to the above data is the JSON snippet below:
Products:
[
{
"id":1,
"name":"Product 1",
"price":3444,
"type":1
},
{
"id":2,
"name":"Product 2",
"price":3444,
"type":2
},
{
"id":3,
"name":"Product 3",
"price":3444,
"type":3
},
{
"id":4,
"name":"Product 4",
"price":3444,
"type":1
},
{
"id":5,
"name":"Product 5",
"price":3444,
"type":2
}
]
and Type model:
[
{
"id": 1,
"type": "A"
},
{
"id": 2,
"type": "B"
},
{
"id": 3,
"type": "C"
},
]
So I want to convert them to a new object like this:
data class NewProduct(val id:String,val name:String,val price:Float,val type:String)
It looks like:
var products = mutableListOf<Product>(
Product("1", "Product 1", 34f, 1),
Product("2", "Product 2", 34f, 2),
Product("3", "Product 3", 34f, 3),
Product("4", "Product 4", 34f, 1),
Product("5", "Product 5", 34f, 2),
)
var types = mutableListOf<Type>(
Type(1, "A"), Type(2, "B"),
Type(3, "C"),
)
// i want to convert to NewProduct list
products.map { products-> }
Can you help me with this problem?
You can do
products.map { product ->
NewProduct(
product.id,
product.name,
product.price,
types.first { type -> type.id == product.type }.name
)
}
You can first convert types into a map to access the types by id much faster:
val typeMap: Map<Int, String> = types.associateBy(Type::id, Type::name)
// {1=Type(id=1, name=A), 2=Type(id=2, name=B), 3=Type(id=3, name=C)}
Then map the products
val productsByType: List<NewProduct> = products.map {
NewProduct(
id = it.id,
name = it.name,
price = it.price,
type = typeMap[it.type] ?: ""
)
}
/**
[NewProduct(id=1, name=Product 1, price=3444.0, type=A),
NewProduct(id=2, name=Product 2, price=3444.0, type=B),
NewProduct(id=3, name=Product 3, price=3444.0, type=C),
NewProduct(id=4, name=Product 4, price=3444.0, type=A),
NewProduct(id=5, name=Product 5, price=3444.0, type=B)]
*/
This way you can do it with O(n) complexity.
I have a variables of type var students = List<StudentData>. I need to create a map with the following structure: Map<String, Map<Int, StudentData>>.
StudentData has information like: studentID, classId, courseA, courseB, courseC etc.
So for the map would be the following: Map<studentID, Map <classId, StudentData>>. Meaning that for every student, I need a map of his classId and all the information.
How can I achieve this using kotlin ?
var indexByCourse = Map<String, Map<Int, StudentData>>
students.forEach {
student -> indexByCourse.getOrPut(student.studentID, {mutableSetOf()}.add(??)
}
Not sure how to approach this problem. Any guidance is appreciated!
You can try the below way to map classId with it's corresponding information.
fun testFunction() {
//for holding student data
val students = ArrayList<StudentData>()
students.add(StudentData(1, 10, "course a", "course 3"))
students.add(StudentData(2, 11, "course b", "course 6"))
students.add(StudentData(3, 12, "course c", "course 2"))
students.add(StudentData(4, 13, "course d", "course 5"))
//For holding course
val indexByCourse = hashMapOf<Int, HashMap<Int, StudentData>>()
students.forEachIndexed { index, studentData ->
val studentSubData = hashMapOf(studentData.classId to studentData)
indexByCourse[studentData.studentID] = studentSubData
}
//Fetch the student data based on studentID
println(indexByCourse[3])
}
and StudentData class for holding the values
data class StudentData(var studentID: Int, var classId: Int, var courseA: String, var courseB: String)
data class StudentData(
val studentID: String,
val classId: Int,
val courseA: String? = "",
val courseB: String? = "",
val courseC: String? = ""
)
val students = listOf(
StudentData("1", 100, "Course 1"),
StudentData("2", 100, "Course 1", "Course 2", "Course 3"),
StudentData("3", 100, "Course 2", "Course 3"),
StudentData("4", 200, "Course 1", "Course 3", "Course 3"),
StudentData("5", 200, "Course 1", "Course 2")
)
val result = students
.groupBy { studentData -> studentData.studentID }
.map { (studentID, values) ->
studentID to values
.groupBy { studentData -> studentData.classId }
.map { (classId, values) -> classId to values.first() }
.toMap()
}
.toMap()
result.forEach(::println)
Output:
1={100=StudentData(studentID=1, classId=100, courseA=Course 1, courseB=, courseC=)}
2={100=StudentData(studentID=2, classId=100, courseA=Course 1, courseB=Course 2, courseC=Course 3)}
3={100=StudentData(studentID=3, classId=100, courseA=Course 2, courseB=Course 3, courseC=)}
4={200=StudentData(studentID=4, classId=200, courseA=Course 1, courseB=Course 3, courseC=Course 3)}
5={200=StudentData(studentID=5, classId=200, courseA=Course 1, courseB=Course 2, courseC=)}
I have a JSON with some data and I would like to print as follows
10 REGISTER 1, KP SUM 2081,606
20 REGISTER 2 CH SUM 0,22
Where the general sum is calculated by the total sum of the items according to the code.
Following the rule, first multiply the quantity by the unit and then add all the items that have the same code.
Example:
code 10
SUM = 0,0200000 * 7,40 + 10,0000000 * 200,31 + 0,5690000 * 40,19 + 0,7890000 * 70,33
The same goes for the other codes that appear in JSON
My JSON
[
{
"code": 10,
"description": "REGISTER 1",
"unity": "KP",
"typeItem": "I",
"itemCode": 1,
"descriptionItem": "ITEM",
"unityItem": "UN",
"quantity": "0,0200000",
"valueUnity": "7,40"
},
{
"code": 10,
"description": "REGISTER 1",
"unity": "KP",
"typeItem": "I",
"codeItem": 2,
"descriptionItem": "ITEM 2",
"unityItem": "UN",
"quantity": "10,0000000",
"valueUnity": "200,31"
},
{
"code": 10,
"description": "REGISTER 1",
"unity": "KP",
"typeItem": "I",
"codeItem": 88248,
"descriptionItem": "ITEM 3",
"unityItem": "H",
"quantity": "0,5690000",
"valueUnity": "40,19"
},
{
"code": 10,
"description": "REGISTER 1",
"unity": "KP",
"typeItem": "I",
"codeItem": 88267,
"descriptionItem": "ITEM 4",
"unityItem": "N",
"quantity": "0,7890000",
"valueUnity": "70,33"
},
{
"code": 20,
"description": "REGISTER 2",
"unity": "CH",
"typeItem": "I",
"codeItem": 1,
"descriptionItem": "ITEM 1",
"unityItem": "H",
"quantity": "30,0000000",
"valueUnity": "0,17"
},
{
"code": 20,
"description": "REGISTER 2",
"unity": "CH",
"typeItem": "I",
"codeItem": 2,
"descriptionItem": "ITEM 2",
"unityItem": "H",
"quantity": "3,0000000",
"valueUnity": "0,07"
}
]
My class Java
public class MyJson {
#SerializedName("code")
#Expose
private Integer code;
#SerializedName("description")
#Expose
private String description;
#SerializedName("unity")
#Expose
private String unity;
#SerializedName("typeItem")
#Expose
private String typeItem;
#SerializedName("codeItem")
#Expose
private Integer codeItem;
#SerializedName("descriptionItem")
#Expose
private String descriptionItem;
#SerializedName("unityItem")
#Expose
private String unityItem;
#SerializedName("quantity")
#Expose
private String quantity;
#SerializedName("valueUnity")
#Expose
private String valueUnity;
private Double total;
}
My Program
public static void main(String[] args) {
Gson gson = new Gson();
try {
File jsonFile = new File("C:\\my_json.json");
InputStreamReader reader = new InputStreamReader(new FileInputStream(jsonFile), "UTF-8");
BufferedReader jsonBuffer = new BufferedReader(reader);
MyJson[] myJsonArray = gson.fromJson(jsonBuffer, MyJson[].class);
BigDecimal valueUnity = BigDecimal.ZERO;
BigDecimal sumTotal = BigDecimal.ZERO;
//
Set<MyJson> list = new HashSet<>();
for(MyJson myJson : myJsonArray) {
if(checkStringNullOrEmpty(myJson.getQuantity()) && checkStringNullOrEmpty(myJson.getValueUnity())) {
if(myJson.getCode().equals(myJson.getCode())) {
String value1 = myJson.getQuantity().replaceAll( "," , "." ).trim();
String value2 = myJson.getValueUnity.replaceAll( "," , "." ).trim();
BigDecimal quantity = new BigDecimal(value1);
BigDecimal valueUnit = new BigDecimal(value2);
valueUnity = quantity.multiply(valueUnit);
somaTotal = sumTotal.add(valueUnity);
String resultado = String.format(Locale.getDefault(), "%.2f", valueUnity);
String sumTotal2 = String.format(Locale.getDefault(), "%.2f", sumTotal);
myJson.setTotal(new Double(sumTotal2.replaceAll( "," , "." ).trim()));
list.add(myJson);
}
}
}
for(MyJson myJson : list) {
StringBuilder builer = new StringBuilder();
builer.append(myJson.getCode()).append(" ");
builer.append(myJson.getDescription().toUpperCase()).append(" ");
builer.append(myJson.getUnity().toUpperCase()).append(" ");
builer.append(myJson.getTotal());
System.out.println(builer.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static boolean checkStringNullOrEmpty(String value) {
if(!value.isEmpty()) {
return true;
} else {
return false;
}
}
Exit program
The calculation is being done wrong when using the Set
10 REGISTER 1, KP SUM 130,33
20 REGISTER 2 CH SUM 439,18
You cannot keep track of multiple running totals (i.e. one for each code) using one total. Instead you will need one total for each different code.
I would recommend that you use a Map<Integer, MyJson> for this purpose. This would store a number of MyJson objects which you could look up by their code. When handling each MyJson object, you check to see if you already have a MyJson object with the same code: if you do then you add to its total, otherwise you add your MyJson object to the map.
Get rid of your Set<MyJson> variable (which you have somewhat confusingly named list) and replace it with the following
Map<Integer, MyJson> jsonsByCode = new LinkedHashMap<>();
(You can use a HashMap<> instead of a LinkedHashMap<> here: I chose to use a LinkedHashMap<> because it keeps its entries in the same order they were inserted into it.)
Then, replace all lines from somaTotal = sumTotal.add(valueUnity); to list.add(myJson); with
if (jsonsByCode.containsKey(myJson.getCode())) {
// We've seen this code before, so add the value
// to the total.
MyJson matchingJson = jsonsByCode.get(myJson.getCode());
matchingJson.setTotal(matchingJson.getTotal() + valueUnity.doubleValue());
} else {
// First time seeing this code, so set its total
// and add it to the map.
myJson.setTotal(valueUnity.doubleValue());
jsonsByCode.put(myJson.getCode(), myJson);
}
(Note that BigDecimal values such as valueUnity have a .doubleValue() method on them, which is the easiest way to convert them to a double.)
Then, in the for loop below, where you are printing out the values, replace list with jsonsByCode.values().
I made these changes to your program and it generated the following output:
10 REGISTER 1 KP 2081.60648
20 REGISTER 2 CH 5.31
Incidentally, your code also contains the following if statement:
if(myJson.getCode().equals(myJson.getCode())) {
// ....
}
You are comparing myJson.getCode() against itself, so this condition will always be true (unless of course myJson.getCode() returns null, in which case you get a NullPointerException). You can just get rid of this check, it doesn't do anything useful.
This question already has answers here:
Java string to date conversion
(17 answers)
String to LocalDate
(5 answers)
how to convert java string to Date object [duplicate]
(5 answers)
Closed 5 years ago.
When I try to type a date in the part of the code where null is listed it wont work. They are date variables but I dont know how to just hard code a date. If i put 02/05/2018 where the null is. It will ask me to make it a string but I want it to go in as a date.
Just like how I randomly type in a customer or a number I would like to randomly type in a date.
DTO
private Long id;
private String name;
private long nmcAcctNo;
private int hubId;
private Date createTime;
private Date updateTime;
public CustomerDTO()
{
}
public CustomerDTO(Long id, String name, long nmcAcctNo, int hubId, Date createTime, Date updateTime)
{
super();
this.id = id;
this.name = name;
this.nmcAcctNo = nmcAcctNo;
this.hubId = hubId;
this.createTime = createTime;
this.updateTime = updateTime;
}
REST
// Your implementation should pull the actual list of customers from the database.
List<CustomerDTO> fakeCustomerList = new ArrayList<CustomerDTO>();
fakeCustomerList.add(new CustomerDTO(1L, "Customer 1", 1, 1, null, null));
fakeCustomerList.add(new CustomerDTO(2L, "Customer 2", 2, 1, null, null));
fakeCustomerList.add(new CustomerDTO(3L, "Customer 3", 3, 1, null, null));
fakeCustomerList.add(new CustomerDTO(4L, "Customer 4", 4, 1, null, null));
fakeCustomerList.add(new CustomerDTO(5L, "Customer 5", 5, 1, null, null));
fakeCustomerList.add(new CustomerDTO(6L, "Customer 6", 6, 2, null, null));
fakeCustomerList.add(new CustomerDTO(7L, "Customer 7", 7, 2, null, null));
fakeCustomerList.add(new CustomerDTO(8L, "Customer 8", 8, 2, null, null));
fakeCustomerList.add(new CustomerDTO(9L, "Customer 9", 9, 3, null, null));
fakeCustomerList.add(new CustomerDTO(10L, "Customer 10", 10, 4, null, null));
return fakeCustomerList;
}
This is because you are typing a String object and not a Date one. What you need is String to Date conversion as follows.
String dateString= "05-02-2018";
DateFormat dateFormater = new SimpleDateFormat("dd-MM-yyyy");
Date aux;
try {
aux = dateFormater.parse(dateString);
} catch (ParseException e) {
e.printStackTrace();
}
Then you can pass the aux variable where you have null.
If you don't want variable creation you can follow other approach passing the following code instead of null
new GregorianCalendar(2018, 5, 2).getTime();
Using Vaadin 6.x and Vaadin Charts, I am playing around with BasicColumn (http://demo.vaadin.com/charts/#BasicColumn).
I want the user to choose bar column colors on the screen. I correctly get the color from user however I couldn't manage to set colors of the column bars dynamically.
I know it is pretty simple with DataSeriesItem however there is no color attribute for ListSeries.
Is there a way to set the colors of bars on BasicColumn?
This is my implementation for DataSeries. But as you set the color on PlotOptionsColumn it should as well work for ListSeries:
pingDropoutSr=new DataSeries();
PlotOptionsColumn dropOptions= new PlotOptionsColumn();
dropOptions.setColor( SolidColor.GREEN ); //Color is an interface only
pingDropoutSr.setPlotOptions(dropOptions);
I faced the same issue here, and found a solution using PlotOptionsColumn.
//Hard Coded Values
String months[] = { "DataSet 1", "DataSet 2", "DataSet 3", "DataSet 4", "DataSet 5"};
int dataArray[][] = {
{ 8, 13, 7, 4 },
{ 23, 1, 30, 7 },
{ 37, 3, 22, 2 },
{ 13, 23, 4, 3 },
{ 3, 10, 9, 5 },
};
int counter = 0;
// Data series for each numeric column in the table
for (int month = 0; month < 4; month++) {
ListSeries series = new ListSeries();
PlotOptionsColumn options = new PlotOptionsColumn();
options.setColor(colors[counter++]);
series.setPlotOptions(options);
series.setName(months[month]);
// The rows of the table
for (int data = 0; data < dataArray.length; data++) {
series.addData(dataArray[data][month]);
}
conf.addSeries(series);
}