I've wrote a method in my implementation of my interface that takes a linked list in parameter and has to return an arraylist of all the items that exists already and weren't added to the class list.
Here's the signature:
public List<T> addBegining(ListeOfEmployees<T> list);
My methode add's the elements in the linked list of the class in inverse.
Lets say the parameter list:
Employee1
Employee2
Employee3
Employee4
Employee5
Actual list in the class:
Employee2
Employee4
Employee5
It's suppose to return an ArrayList in the same order of the parameter list:
1-Employee2
2-Employee4
3-Employee5
But it returns an ArrayList like this:
1-Employee5
2-Employee4
3-Employee2
I used a while() to cycle thru my parametered list but it goes from begining to end.
I don't know how I can cycle thrue the parameterized list but from the end to the beginning.
I cannot use a pointer at the end of the list for this method.
I'm out of solutions here.
Here's what i've done so far:
public List<T> addBegining(ListeOfEmployees<T> list) {
List<T> res = null;
T return;
Iterator<T> it = list.iterator();
while (it.hasNext() && list != null) {
return = it.next();
if (this.hasElement(return)) {
if (res == null) {
res = new ArrayList<T>();
}
res.add(retour);
} else {
this.addBegining(retour);
nbElm++;
}
}
return res;
}
Related
I would like to avoid the mutation of the input list of iterators tests by others. I only want others to run on a deep copy of tests.
How can this be achieved in Java?
Here is an example showing the effect of the mutation on tests. Both of the two parts are sorting the input. But the second part has nothing to be sorted since the mutation from the first part iterated the iterators to the end.
You can run the following example online here:
https://onlinegdb.com/NC4WzLzmt
import java.util.*;
public class ImmutableExample {
public static void main(String[] args) {
System.out.println("sort on demand");
List<Iterator<Integer>> mutableTests = Arrays.asList(
Arrays.asList(1, 2).iterator(),
Arrays.asList(0).iterator(),
Collections.emptyIterator()
);
List<Iterator<Integer>> tests = Collections.unmodifiableList(mutableTests);
MergingIterator mergingIterator = new MergingIterator(tests);
while (mergingIterator.hasNext()) {
System.out.println(mergingIterator.next());
}
System.out.println("sort all at once");
/* uncomment the following will see the same result:*/
// tests = Arrays.asList(
// Arrays.asList(1, 2).iterator(),
// Arrays.asList(0).iterator(),
// Collections.emptyIterator()
// );
MergeKSortedIterators sol = new MergeKSortedIterators();
Iterable<Integer> result = sol.mergeKSortedIterators(tests);
for (Integer num : result) {
System.out.println(num);
}
}
}
class PeekingIterator implements Iterator<Integer>, Comparable<PeekingIterator> {
Iterator<Integer> iterator;
Integer peekedElement;
boolean hasPeeked;
public PeekingIterator(Iterator<Integer> iterator) {
this.iterator = iterator;
}
public boolean hasNext() {
return hasPeeked || iterator.hasNext();
}
public Integer next() {
int nextElem = hasPeeked ? peekedElement : iterator.next();
hasPeeked = false;
return nextElem;
}
public Integer peek() {
peekedElement = hasPeeked ? peekedElement : iterator.next();
hasPeeked = true;
return peekedElement;
}
#Override
public int compareTo(PeekingIterator that) {
return this.peek() - that.peek();
}
}
class MergingIterator implements Iterator<Integer> {
Queue<PeekingIterator> minHeap;
public MergingIterator(List<Iterator<Integer>> iterators) {
// minHeap = new PriorityQueue<>((x, y) -> x.peek().compareTo(y.peek()));
minHeap = new PriorityQueue<>();
for (Iterator<Integer> iterator : iterators) {
if (iterator.hasNext()) {
minHeap.offer(new PeekingIterator(iterator));
}
}
}
public boolean hasNext() {
return !minHeap.isEmpty();
}
public Integer next() {
PeekingIterator nextIter = minHeap.poll();
Integer next = nextIter.next();
if (nextIter.hasNext()) {
minHeap.offer(nextIter);
}
return next;
}
}
class MergeKSortedIterators {
public Iterable<Integer> mergeKSortedIterators(List<Iterator<Integer>> iteratorList) {
List<Integer> result = new ArrayList<>();
if (iteratorList.isEmpty()) {
return result;
}
PriorityQueue<PeekingIterator> pq = new PriorityQueue<>();
for (Iterator<Integer> iterator : iteratorList) {
if (iterator.hasNext()) {
pq.add(new PeekingIterator(iterator));
}
}
while (!pq.isEmpty()) {
PeekingIterator curr = pq.poll();
// result.add(curr.peek());
// cannot use this one as hasNext() checks on `hasPeeked`
result.add(curr.next());
if (curr.hasNext()) {
pq.add(curr);
}
}
return result;
}
}
This question seems to be based on a misunderstanding ... or two.
How can I prevent mutation of a list of iterators?
You need to distinguish between the mutability of a list, and the mutability of the items in the list. I think you are actually asking about the latter. (And as such, the list is not really relevant to the question. As we shall see.)
I would like to avoid the mutation of the input list of iterators tests by others.
Again, you appear to be asking about the list, but I think you actually mean to ask about the iterators.
I only want others to run on a deep copy of tests.
This implies you want the iterators to be immutable.
Here's the problem:
An Iterator is an inherently stateful / mutable object. Indeed, there is no way to implement next() without mutating the iterator object.
Iterator objects are typically not deep copyable. They typically don't support clone() or public constructors, and they typically do not implement Serializable. (Indeed, if they were serializable, the semantics of serialize / deserialize would be problematic.)
So basically, your idea of a list of immutable iterators or a list that (somehow) produces deep copies of iterators is not practical.
You commented:
So List<Iterator<Integer>> tests = Collections.unmodifiableList(mutableTests); cannot produce an unmodifiable list for List<Iterator<Integer>>?
Well, yes it can. But that doesn't solve the problem. You need a list of unmodifiable iterators rather than an unmodifiable list of iterators.
Possible solutions:
You could just recreate the list of iterators from their base collections for each test run.
Use Iterable instead of Iterator. The collection types you are using all implement Iterable, and the third iterator could be created from an empty list.
List<Iterable<Integer>> tests = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(0),
Collections.emptyList()
);
// to use them ...
for (Iterable<Integer> iterable : tests) {
Iterator<Integer> iterator = iterable.iterator();
// etc ...
}
If your iterators could not be recreated (for example, if you were iterating a source that couldn't be created or "rewound"), you could conceivably implement a caching iterator wrapper that remembered all of the elements in the iteration sequence and could either reset to the start of the sequence, or generate a new iterator to replay the sequence. (But that would be overkill here.)
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
I have a mapper method which accepts a lambda function from the object calling it.
LambdaList<String> strings = new LambdaList<String>("May",
"the", "force", "be", "with", "you");
list = strings.map(x -> x.length());
assert list.equals(new LambdaList<Integer>(3, 3, 5, 2, 4, 3))
: "map() failed. Result is " + list + ".";
The map method will then iterate though the list and return a new list once the lambda has been applied.
/**
* Returns a list consisting of the results of applying the given function
* to the elements of this list.
* #param <R> The type of elements returned.
* #param mapper The function to apply to each element.
* #return The new list.
*/
public <R> LambdaList<R> map(Function<? super T, ? extends R> mapper) {
ArrayList<R> newList = new ArrayList<>();
for(T item: this){
newList.add(mapper.apply(item));
}
return new LambdaList<R>(newList);
}
The lambda list is set up as below:
class LambdaList<T> {
private ArrayList<T> list;
public LambdaList() {
list = new ArrayList<T>();
}
#SafeVarargs
public LambdaList(T... varargs) {
list = new ArrayList<T>();
for (T e: varargs) {
list.add(e);
}
}
private LambdaList(ArrayList<T> list) {
this.list = list;
}
public LambdaList<T> add(T e) {
ArrayList<T> newList = new ArrayList<>();
newList.addAll(list);
newList.add(e);
return new LambdaList<T>(newList);
}
I tried using T item: this to refer to the object itself but that doesn't work. How would i go about implementing this method?
To be able to write an enhanced for loop, the object needs to be iterable.
class LambdaList<T> implements Iterable<T> { ... }
You will then need to implement a public Iterator<T> iterator() method, which will probably look like return internalList.iterator();.
I have a mapper method which takes list of entities called Claim iterates over them and maps to CompensationDTO and adds to list, but entity can contain lists of children entities which type is also Claim and those children can also contain list of Claims, so to iterate over them all is best to use recursion but i'm not sure how it should be written
private List<CompensationDTO> mapToDTO(List<Claims> claims) {
List<CompensationsDTO> compensations = new ArrayList<>();
if (claims.isEmpty()) {
return new ArrayList<>();
}
for (Claim claim : claims) {
CompensationDTO compensationDTO = new CompensationDTO();
compensationDTO.setId(claim.getId());
compensationDTO.setAmount(claim.getAmount());
compensationDTO.setType(claim.getType());
compensations.add(compensationDTO);
mapToDTO(claim.getChildrenClaims());
}
return compensations;
}
I understand that the base case should return empty list but i don't know where to put the recursive function call mapToDTO(claim.getChildrenClaims());
Did you try to add compansations.addAll()?:
private List<CompensationDTO> mapToDTO(List<Claims> claims) {
List<CompensationsDTO> compensations = new ArrayList<>();
if (claims.isEmpty()) {
return new ArrayList<>();
}
for (Claim claim : claims) {
CompensationDTO compensationDTO = new CompensationDTO();
compensationDTO.setId(claim.getId());
compensationDTO.setAmount(claim.getAmount());
compensationDTO.setType(claim.getType());
compensations.add(compensationDTO);
compensations.addAll(mapToDTO(claim.getChildrenClaims()));
}
return compensations;
}
mapToDTO returns List<CompensationDTO> and you need to add these elements to your local list.
List<CompensationDTO> rec = mapToDTO(claim.getChildrenClaims());
compensations.addAll(rec);
To create a List, why doesn't Java allow them to be created then elements added one by one?
This works:
public static List<TrackedItem> create(List<Item> items)
{
TrackedItem[] arr = new TrackedItem[items.size()];
int i = 0;
for (Item item : items)
{
arr[i] = TrackedItem.createOrUpdate(item);
i++;
}
return java.util.Arrays.asList(arr);
}
This does not work (tracked.add() causes a NullPointerException):
public static List<TrackedItem> create(List<Item> items)
{
List<TrackedItem> tracked = java.util.Collections.emptyList();
for (Item item : items)
{
tracked.add(TrackedItem.createOrUpdate(item));
}
return tracked;
}
java.util.Collections.emptyList();
static
List
emptyList()
Returns the empty list (immutable).
That means, you will not be able to change this list.
Its defined:
static List EMPTY_LIST
The empty list (immutable).
Quotes from Java sun reference
Edit:
To create a new list you could use e.g.
List myList = new ArrayList<MyClass>();
Use the following syntax:
public static List<TrackedItem> create(List<Item> items)
{
List<TrackedItem> tracked = new ArrayList<TrackedItem>();
for (Item item : items)
{
tracked.add(TrackedItem.createOrUpdate(item));
}
return tracked;
}
This might be a misunderstanding.
Even if it is called emptyList, it isn't a list which is just empty and ready to be populated. This emptyList is designed to be empty at all times. You can't add to this special list.
To get a 'usable' empty list you can either
List<String> list = new ArrayList<String>(); // create a new one or
list.add("if you have an list");
list.clear(); // just clear it
create a new arrayList by :
List<T> tracked = new ArrayList<T>();
List is only an interface ... you can't make a new one. you only can implement it.