Need help in list Java - java

Not sure how I can achieve this.
I have a object list, where it consists of multiple data example
ABC1231211
ABC1231111
ABC4562222
ABC4562456
Now I trying to seperate the list according to their code, which is 123 and 456, and add header and tailer to them. So my expected result would be
Head
ABC1231211
ABC1231111
Tail
Head2
ABC4562222
ABC4562456
Tail2
But the result I get is
Head
ABC1231211
Tail
Head
ABC1231111
Tail
Head2
ABC4562222
Tail2
Head2
ABC4562456
Tail2
Code
#Override
public List process(List<Detail> l) throws Exception {
for (Detail d : l) {
if (d.Code().equals("123")) {
list = generateS(d);
}
if (d.Code().equals("456")) {
list = generateR(d);
}
}
return list;
}
public List<String> generateS(Detail d) throws Exception {
try {
list.add(new HDR("Head").getHeader());
DetailL x = new DetailL();
x.setType(d.getType());
....
list.add(x.getDetail());
list.add(new TLR("Tail").getTailer());
} catch (Exception ex) {
throw new BatchException(DetailProcessor.class, ex);
}
return list;
}
Any help would be much appreciated

If you're using Java 8, you can use streams:
public void process(List<Detail> details) throws Exception {
Map<String, List<Detail>> byCode =
details.stream().collect(Collectors.groupingBy(Detail::getCode));
byCode.entrySet().stream().forEach(entry -> {
System.out.println(headerFromType(entry.getKey()));
entry.getValue().foreach(System.out::println);
System.out.println(tailFromType(entry.getKey()));
}
with headerFromType and tailFromType returning "Head"/"Head2" or "Tail"/"Tail2", depending on the given type.

You are generating a new head and tail for each element instead of adding to the already-generated list.
For each Detail, you should first check if the list exists, and if it doesn't, then call generateS or generateR as appropriate. If the list exists, you want to call e.g. sList.add(sList.size()-1, d.getDetail()). You'll of course want to replace the call d.getDetail() with the value that's supposed to go into the list or a method call that returns that value.
Then you probably want to use list.addAll(sList) to add the generated lists' contents to list.
Another solution is to generate the combined list on demand, and store the two lists separately. In that case, you would check if the corresponding list is null in the beginning of generateS or generateR, and initialize it if it is.

You create a new header and a new tail every time you call generateS or generateR but you should just create a new header once if you find a new code ( for example 123).
Solution: You collect your details into a list before you call generateS or generateR and put all the details from collected list into your DetailL.

Here is another implemetation that takes another approach:
private void go() {
List<String> list = new ArrayList<>();
list.add("ABC1231211");
list.add("ABC1231111");
list.add("ABC4562222");
list.add("ABC4562456");
String lastTag = null;
int startPos = 0;
for (int i = 0; i < list.size(); i++) {
String tag = list.get(i).substring(3, 6);
if (!tag.equals(lastTag) && lastTag != null) {
print(list.subList(startPos, i));
startPos = i;
}
lastTag = tag;
}
print(list.subList(startPos, list.size()));
}
private void print(List<String> list) {
System.out.println("Head");
for (String item : list) {
System.out.println(item);
}
System.out.println("Tail");
}
Simply "If you come accross an element with a different tag, print the previous sublist". (And print whatever is left at the end since that sublist's printout is not triggered by a new tag.)

Related

Weird situation with an arraylist and parallelStream

I have a parallel stream because the task is really slow, I will paste the code below. The situation is this.
I have an arrayList, I need to do something with each object in that list (this is slow) and add the object to a temporal list, the process in the stream ends ok, I think, because I can see each object processed with logs.
When the stream ends, sometimes, the temporal list has n-1 objects or one as null.
Any idea?
With this sample code the errors are not happening, but the logic is the same but without the business logic.
public class SampleCode {
public List<SomeObject> example(List<SomeObject> someObjectList) {
List<SomeObject> someObjectListTemp = new ArrayList<>();
someObjectList.parallelStream().forEach(someObject -> {
List<ExtraData> extraDataList = getExtraData(someObject.getId());
if (extraDataList.isEmpty()) {
someObjectListTemp.add(someObject);
} else {
for (ExtraData extraData : extraDataList) {
SomeObject someObjectTemp = null;
someObjectTemp = (SomeObject) cloneObject(someObject);
if (extraData != null) {
someObjectTemp.setDate(extraData.getDate());
someObjectTemp.setData2(extraData.getData2());
}
if (someObjectTemp == null) {
System.out.println("Warning null object"); //I NEVER see this
}
someObjectListTemp.add(someObjectTemp);
System.out.println("Added object to list"); //I Always see this the same times as elements in original list
}
}
});
if (someObjectListTemp.size() < 3) {
System.out.println("Error: There should be at least 3 elements"); //Some times one object is missing in the list
}
for (SomeObject someObject : someObjectListTemp) {
if (someObject == null) {
System.out.println("Error: null element in list"); //Some times one object is null in the list
}
}
return someObjectListTemp;
}
Could you try to use the flatMap method instead of foreach?
flatMap takes a list of lists and put all their elements in a single list.
This way you do not use another ArrayList to store your temporary objects.
I feel that this might be the issue, because parallelStream is multi threading and ArrayList is not synchronised
List<SomeObject> someObjectListTemp = someObjectList.parallelStream()
.map(so -> processSomeObject(so)) // makes a stream of lists (Stream<List<SomeObject>>)
.flatMap(Collection::stream) // groups all the elements of all the lists in one stream (Stream<Someobject>)
.collect(Collectors.toList()); // transforms the stream into a list (List<SomeObject>)
And stick your code in a separate method processSomeObject which returns a list of SomeObject:
static List<SomeObject> processSomeObject(SomeObject someObject) {
List<ExtraData> extraDataList = getExtraData(someObject.getId());
List<SomeObject> someObjectListTemp = new ArrayList<>();
if (extraDataList.isEmpty()) {
someObjectListTemp.add(someObject);
} else {
for (ExtraData extraData : extraDataList) {
SomeObject someObjectTemp = (SomeObject) cloneObject(someObject);
if (extraData != null) {
someObjectTemp.setDate(extraData.getDate());
someObjectTemp.setData2(extraData.getData2());
}
someObjectListTemp.add(someObjectTemp);
System.out.println("Added object to list");
}
}
return someObjectListTemp;
}
A small example would be
public static void main(String[] args) {
List<Object> test = new ArrayList<>();
IntStream.range(0, 100000).parallel().forEach(i -> test.add(new Object()));
for(Object o : test) {
System.out.println(o.getClass());
}
}
i'ts because ArrayList is not threadsafe and the internal array gets screwed

Removing the last element of an ArrayList

I'm new to Java and I'm stuck with an exercise I've been trying to solve for over a week now and I don't know what I'm doing wrong.
I need to delete the last elements of an ArrayList, an integer in this case.
The problem is that when I run the test, it still returns the old values.
public static void removeLastOccurrence(int x, ArrayList<Integer> list) {
if (list != null && !list.isEmpty()) {
list.remove(list.size()-1);
}
}
I also tried using list.remove(list.lastIndexOf(x));
But it still returns the same list when I run this test.
public class UTest{
#Test
public void testMultipleLast() {
ArrayList<Integer> input = new ArrayList<Integer>(asList(1,1,3,5,7,1,5,9,1));
ArrayList<Integer> result = new ArrayList<Integer>(asList(1,1,3,5,7,1,5,9));
Solution.removeLastOccurence(1, input);
assertEquals(result, input);
}
}
Would be nice if someone could help and tell me what I'm missing as it's getting quite frustrating as I've the feeling that I'm just missing a small piece of the puzzle.
Your test should be like below. In the test code in the original post, you are not actually invoking the method that you are trying to test.
public class UTest
{
#Test
public void testMultipleLast() {
ArrayList<Integer> input = new ArrayList<Integer>(asList(1,1,3,5,7,1,5,9,1));
ArrayList<Integer> result = new ArrayList<Integer>(asList(1,1,3,5,7,1,5,9));
// int x = ?
ArrayList<Integer> actual = SomeClass.removeLastOccurrence(x, input)
assertEquals(result, actual);
}
}
and the removeLastOccurrence() method can do the following
if(list != null && !list.isEmpty()){
list.remove(list.size() - 1);
}
It's because you are not removing any elements.
list.get(list.size()-1);
does not remove elements.
use
list.remove(list.size()-1)
instead.
According to Java ArrayList API with get(int index) method you just obtain the element in index position in your ArrayList.
This is the method you are looking for:
public static void removeLastOccurrence(int x, ArrayList<Integer> list) {
if (list != null && !list.isEmpty()) {
list.remove(list.size()-1);
}
}
You have to use :
list.remove(list.size()-1);
And return your new list so you can use :
public static ArrayList<Integer> removeLastOccurrence(int x, ArrayList<Integer> list) {
if (list != null && !list.isEmpty()) {
list.remove(list.size()-1);
}
return list;
}
If you pass your list as argument to the method it becomes a local variable. Therefore you are not removing the element from your input list but only from the local variable list. The solution is to return that local list from your method or to remove the element directly from your "input" list using the same code. The x parameter in your original method is unnecessary.

Derivative method is changing original list when it should be returning newList

I have an assignment where I am manipulating polynomials using linked lists. One portion of the assignment is to take the first, second and third derivatives of a polynomial. All my methods work individually. However, after running the first derivative method, it changes original input list to what the first derivative is–something I do not want.
Here is my method:
public ObjectList derivative(ObjectList list1) {
newList = new ObjectList();
ObjectListNode p = list1.getFirstNode();
while (p != null) {
Term t1 = (Term) p.getInfo();
if (t1.getExp() == 0) {
t1.setCoeff(0);
attach(0,0);
p = p.getNext();
}
else {
t1.setCoeff(t1.getCoeff()*t1.getExp());
t1.setExp(t1.getExp() - 1);
attach(t1.getCoeff(), t1.getExp());
p = p.getNext();
}
}
return newList;
}
As you can see, the return for the derivative method is newList. However, the method is changing the original list.
In my main, I have something like this:
ObjectList poly1;
System.out.println("\nEnter a polynomial (for derivatives): ");
poly1 = p.getPolynomial();
System.out.println("First derivative: ");
p.displayPoly(p.derivative(poly1));
System.out.println("\nTest:");
p.displayPoly(poly1);
poly1 ends up changing.
My input into the console I have been using is : 3x^4+2x^3+1x^2-1x^1+8x^0
This is probably an extremely simple mistake, but for some reason I cannot catch it. Thanks for any help, I appreciate it!
EDIT: The attach method in the derivative method:
private void attach (int coeff, int exp) {
Term t = new Term (coeff, exp);
newList.addLast(t);
}
You are only initializing the newList instance (with newList = new ObjectList()) without putting anything in it, and you are updating the terms of the input list list1.
You didn't post the code of ObjectList and ObjectListNode, so I can't say the exact methods you should call in order to add nodes to newList, but you should add a new node to newList for each node of the input list, initialize it to contain a copy of the respective Term of the input list, and update the Term of the newList instead of the Term of the input list.
EDIT :
You don't pass newList to attach, so the list you are adding terms to is not the same list you initialize in the derivative method. In addition, you shouldn't call setCoeff and setExp on the terms of the input list, since you don't want to change it.
Therefore you should replace :
t1.setCoeff(0);
attach(0,0);
with :
attach(0,0);
And replace :
t1.setCoeff(t1.getCoeff()*t1.getExp());
t1.setExp(t1.getExp() - 1);
attach(t1.getCoeff(), t1.getExp());
with :
attach(t1.getCoeff()*t1.getExp(), t1.getExp() - 1);
However, if you want to update the newList created in the derivative method, you should either pass the newList to the attach method, or cancel the attach method and move its content to the derivative method :
public ObjectList derivative(ObjectList list1) {
newList = new ObjectList();
ObjectListNode p = list1.getFirstNode();
while (p != null) {
Term t1 = (Term) p.getInfo();
if (t1.getExp() == 0) {
Term t = new Term (0,0);
newList.addLast(t);
p = p.getNext();
}
else {
Term t = new Term (t1.getCoeff()*t1.getExp(), t1.getExp() - 1);
newList.addLast(t);
p = p.getNext();
}
}
return newList;
}

List<String> minus List<String>

I have following code. In the first i tried to set values in the list called 'unavailable'.
Next, in the for each I have to produce a cycle on the list domainStr minus unavailable. How can i do it?
public Result execute(List<String> domainsStr) {
Result result = new Result();
try {
List<String> domains = domainService.findByNames(domainsStr);
result.setUnavailable(domains);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
for (String domain : domainsStr) {
......
}
return result;
}
public static class Result {
private List<String> unavailable = new ArrayList<>();
public List<String> getUnavailable() {
return unavailable;
}
public void setUnavailable(List<String> unavailable) {
this.unavailable = unavailable;
}
}
removeAll(Collection c) is the function which would be the most helpful to you. Having said that, this will work properly only if you have the equals method correctly defined for your Domain object. In this case it is a String so it doesnt matter. But, just to keep it in mind.
so just say, domainsStr.removeAll(result.getUnavailable());
Also, if the Result class is static, why the new object creation here?
Result result = new Result();
This result.setUnavailable(domains);
can be changed to
Result.setUnavailable(domains);
I have to to produce a cycle on the list domainStr minus unavailable.
If I understood correctly, I think you are looking for the removeAll method :
Removes from this list all of its elements that are contained in the
specified collection (optional operation).
domainsStr.removeAll(result.getUnavailable());
for (String domain : domainsStr) {
}
If you want to let domainsStr unchanged, you can create a temporary list and perfom these operations on it.
List<String> tempList = new ArrayList<String>(domainsStr);
tempList.removeAll(result.getUnavailable());
for(String domain : tempList){
.....
I put them into a tempt list so you don't lose the items in the domainsStr list.

dividing arraylist into multiple arraylists

My program creates an arraylist of 5000 to 60000 records depending on time of day. I want to split it into as many arraylists as possible that each arraylist will have 1000 records. I looked at many examples online and tried a few things but I ran into strange problems. Can you please show me an example of this?
Regards!
public static <T> Collection<Collection<T>> split(Collection<T> bigCollection, int maxBatchSize) {
Collection<Collection<T>> result = new ArrayList<Collection<T>>();
ArrayList<T> currentBatch = null;
for (T t : bigCollection) {
if (currentBatch == null) {
currentBatch = new ArrayList<T>();
} else if (currentBatch.size() >= maxBatchSize) {
result.add(currentBatch);
currentBatch = new ArrayList<T>();
}
currentBatch.add(t);
}
if (currentBatch != null) {
result.add(currentBatch);
}
return result;
}
Here's how we use it (assuming emails an a large ArrayList of email addresses:
Collection<Collection<String>> emailBatches = Helper.split(emails, 500);
for (Collection<String> emailBatch : emailBatches) {
sendEmails(emailBatch);
// do something else...
// and something else ...
}
}
where emailBatch would iterate over the collection like this:
private static void sendEmails(Collection<String> emailBatch){
for(String email: emailBatch){
// send email code here.
}
}
You can use the subList http://docs.oracle.com/javase/6/docs/api/java/util/List.html#subList from List to split your ArrayList. The sublist will give you a view of the original list. If you really want to create a new list, separate from the old one, you could do something like:
int index = 0;
int increment = 1000;
while ( index < bigList.size() ) {
newLists.add(new ArrayList<Record>(bigList.subList(index,index+increment));
index += increment;
}
Note you'll have to check for off by one errors here. This is just a quick pseudocode sample.

Categories

Resources