Java - List sorting doesn't work - java

I'm trying to sort a hashmap's by sorting it's keys but it doesn't work.
The sorting criteria is given by the length of a list that is the hashmap's value.
See code below with some unit test.
Class:
package com.fabri.interpreter.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import com.fabri.interpreter.VerbExpr;
import com.fabri.interpreter.ObjectExpr;
public class Environment {
private HashMap<VerbExpr, List<ObjectExpr>> map = new HashMap<VerbExpr, List<ObjectExpr>>();
public List<ObjectExpr> eval(VerbExpr verb) {
return map.get(verb);
}
public void put(VerbExpr verb, ObjectExpr words) {
List<ObjectExpr> values;
if(map.get(verb) == null)
values = new ArrayList<ObjectExpr>();
else
values = map.get(verb);
values.add(words);
map.put(verb, values);
}
public HashMap<VerbExpr, List<ObjectExpr>> getMap() {
return map;
}
public void sort() {
List<VerbExpr> keys = new ArrayList<VerbExpr>(map.keySet());
Collections.sort(keys, new Comparator<VerbExpr>() {
#Override
public int compare(VerbExpr verb1, VerbExpr verb2) {
return map.get(verb1).size()-map.get(verb2).size();
}
});
HashMap<VerbExpr, List<ObjectExpr>> sortedMap = new HashMap<VerbExpr, List<ObjectExpr>>();
for(VerbExpr verb : keys) {
sortedMap.put(verb, map.get(verb));
}
map = sortedMap;
}
}
Testing class:
package com.fabri.interpreter.util;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.fabri.interpreter.ObjectExpr;
import com.fabri.interpreter.VerbExpr;
import com.fabri.interpreter.WordExpr;
public class TestEnvironment {
private Object[] verbExprs;
#Before
public void setUp() {
Environment env = new Environment();
List<WordExpr> words1 = new ArrayList<WordExpr>();
words1.add(new WordExpr("american"));
words1.add(new WordExpr("italian"));
env.put(new VerbExpr("was"), new ObjectExpr(words1));
List<WordExpr> words2 = new ArrayList<WordExpr>();
words2.add(new WordExpr("zero"));
words2.add(new WordExpr("one"));
words2.add(new WordExpr("two"));
env.put(new VerbExpr("is"), new ObjectExpr(words2));
env.sort();
verbExprs = env.getMap().keySet().toArray();
}
#Test
public void testEnvironment() {
assertTrue(((VerbExpr)verbExprs[0]).equals("is"));
assertTrue(((VerbExpr)verbExprs[1]).equals("was"));
}
}

Plain hashmaps are inherently unordered. You can't sort them, or assume anything about the order in which the entries are retrieved when iterating over them. Options:
Use a TreeMap if you want to sort by key.
Use a LinkedHashMap if you want to preserve insertion order (which is what your sort method looks like it assumes)
Create a list of key/value pairs and sort that instead.

As jon said I would suggest keeping an ordered list of keys, and using that to access the inherently unordered hash map.

Related

how could I test Lists in JUnit5?

I got an error when I tried to test 2 ArraysLists.
It seems the error is saying "toArray() is undefined" at my removeEndWith_at method. Could you guys give me an advice how to test these 2 ArraysList?
Thanks.
Java version: jdk-10.0.2
JUnit:5
[ArrayListIterator Class]
import java.util.Iterator;
import java.util.List;
public class ArrayListIterator {
/**
* #param wordsAl : list of words
*/
public List<String> removeEndWith_at(List<String> wordsAl) {
Iterator<String> iterator = wordsAl.iterator();
while (iterator.hasNext()) {
if (iterator.next().endsWith("at"))
iterator.remove();
}
return wordsAl;
}
}
[ArrayListIteratorTest Class]
import static org.junit.Assert.assertArrayEquals;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
class ArrayListIteratorTest {
ArrayListIterator alIterator = new ArrayListIterator();
List<String> actualWords = Arrays.asList("Apple", "Bat", "Orange", "Cat");
#Test
void testremoveEndWith_at() {
actualWords = alIterator.removeEndWith_at(actualWords);
List<String> expectedvalue = Arrays.asList("Apple", "Orange");
assertArrayEquals(expectedvalue.toArray(), actualWords.toArray());
}
}
Look at the
remove() on List created by Arrays.asList() throws UnsupportedOperationException
Arrays.asList()
method just creates a wrapper around the original elements and on this wrapper are not implemented methods which changes its size.
Also look at my implementation of method removeEndWith_at. It is simpler than yours version
/**
* #param wordsAl : list of words
*/
public List<String> removeEndWith_at(List<String> wordsAl) {
wordsAl.removeIf(s -> s.endsWith("at"));
return wordsAl;
}
When comparing two instances of List<String> using Jupiter Assertion API, give assertLinesMatch a try.

Mock spliterator for Iterable implementation when called several times?

I have a problem mocking an Iterable class combined with a call of spliterator(). It all works fine when calling spliterator once, but the second call returns no values.
As the mock always returns the same Spliterator instance, I assume that the state is not reset. Is there a way to do this?
This is the smallest example I could give
The call mapStringToHash is a Lib in real life and can't be changed.
MyIterable is also no object under my control.
package net.test;
import static org.hamcrest.CoreMatchers.is;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.MatcherAssert.assertThat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class SpliteratorTest {
class MyIterable<T> implements Iterable<T> {
private List<T> list;
MyIterable(List<T> list) {
this.list = new ArrayList<>(list);
}
#Override
public Iterator<T> iterator() {
return list.iterator();
}
#Override
public Spliterator<T> spliterator() {
return list.spliterator();
}
}
// this a library method
private Stream<Integer> mapStringToHash(final MyIterable<String> myIterable) {
return StreamSupport.stream(myIterable.spliterator(), false).map(String::hashCode);
}
#Test
public void testSeveralSpliteratorCalls() {
MyIterable myIterable = givenMyIterableMock("a", "b", "c");
Stream<Integer> myIterableHash1 = mapStringToHash(myIterable);
assertThat(myIterableHash1.count(), is(3L));
Stream<Integer> myIterableHash2 = mapStringToHash(myIterable);
assertThat(myIterableHash2.count(), is(3L));
}
private MyIterable givenMyIterableMock(String... values) {
MyIterable myIterable = mock(MyIterable.class);
Spliterator myIterableSpliterator = Arrays.stream(values)
.collect(toList())
.spliterator();
doReturn(myIterableSpliterator).when(myIterable).spliterator();
return myIterable;
}
}
It turns out it's not as circumvent as I thought. It can be done using a custom Answer implementation, but since Answer is a functional interface, the following suffices:
Mockito.when(myIterable.spliterator()).then(invocation -> Arrays.spliterator(values));

Iterate through an ArrayList + Observer Pattern

I have recently tried programming various versions of Iterator and Observer Patterns in Java, but currently I'm stuck at the implementation of both in one project:
What I'm trying to accomplish is to iterate through an ArrayList, which contains elements of type and after each iteration-process to inform the Observer about the change and the containing element.
Also I want to be able to choose the "type" of iterator in my separate classes
Edit: I finally finished the project, hopefully this is the correct version of a "Observer Iterator", any tips on how to improve the code are greatly appreciated, but thanks to everybodys' encouraging tips.
Code:
First of all, the helper class for the Observer interface, which implements the update method. Changes with every iteration process and prints out the element.
package iteratorObserver;
import java.util.List;
public class ConcreteObserver implements Observer{
#Override
public void update(String element) {
System.out.println("The current element is: " + element);
}
}
The actual Observer interface:
package iteratorObserver;
public interface Observer<E> {
void update(String element);
}
Following that, the same by using a ConcreteSubject and an abstract class Subject
The observer pattern requires the getState and setState, so I integrated both into the next method. Getting the element by iterator.next aswell as setting it.
package iteratorObserver;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ConcreteSubject<E> extends Subject implements IteratorStandardFilter<E>{
List<String> listElements = new ArrayList<String>();
private int index;
private Iterator<E> iterator;
public ConcreteSubject(Iterator<E> iterator, List<String> listElements){
index = 0;
this.iterator = iterator;
this.listElements = listElements;
}
public void addElement(String element) {
listElements.add(element);
notifyObservers(element);
}
// check the size of the elements list and return if there are still
// elements left out
#Override
public boolean hasNext() {
if ((listElements.size() == index))
return false;
return true;
}
// iterate to the next element, not sure if it's overridden, since the
// actual next method of the iterator is still in use
#Override
public E next() {
E result = iterator.next();
index++;
notifyObservers((String) result);
return result;
}
}
Subject class, only used for the standard observer methods
package iteratorObserver;
import java.util.ArrayList;
import java.util.List;
public class Subject {
public List<Observer> listObservers = new ArrayList<Observer>();
public void addObserver(Observer observer){
listObservers.add(observer);
}
public void removeObserver(Observer observer){
listObservers.remove(observer);
}
public <E> void notifyObservers(String element){
for(Observer observerHelp : listObservers){
observerHelp.update(element);
}
}
}
Since i want to add various filters, not only the standard list-iterator, i added a class IteratorStandardFilter, as you can see here:
package iteratorObserver;
import java.util.Iterator;
public interface IteratorStandardFilter<E> extends Iterator<E> {
public boolean hasNext();
public E next();
}
And finally, the Test method, the main:
package iteratorObserver;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class iteratorObserverMain {
public static void main(String [] args){
List<String> listElements = new ArrayList<String>();
listElements.add("hello");
listElements.add("there");
listElements.add("everybody");
listElements.add("it");
listElements.add("works");
listElements.add("Thanks for your help. Nice and encouraging forum");
Iterator<String> iterator = listElements.iterator();
ConcreteSubject<String> concreteSubject = new ConcreteSubject<String>(iterator, listElements);
concreteSubject.addObserver(new ConcreteObserver());
while(concreteSubject.hasNext()){
concreteSubject.next();
}
}
}

Sorting in Apache Spark

I am new to Apache Spark and I am reading files from HDFS directory and then filtering and ordering based on condition.
I have two files in a hdfs directory
First file containing data like below
Name:xxxx,currenttime:[timestamp],urlvisited:[url]
Second file containing following information
Name:xxxx,currenttime :[timestamp],downloadfilename:[filename]
First I am filtering the data based on Name and then I am splitting the data using comma and then I am ordering the data using the fields currenttime
So far I have tried
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import scala.Tuple2;
public class SampleVisit {
public static void main(String[] args) {
final String name = args[0];
SparkConf sparkConf = new SparkConf().setAppName("sample");
JavaSparkContext ctx = new JavaSparkContext(sparkConf);
JavaRDD<String> lines = ctx.textFile("hdfs://localhost:9000/sample/*/",1);
JavaRDD<String> filterdata = lines.filter(new Function<String, Boolean>() {
#Override
public Boolean call(String s) {
return s.contains("Name:" + name);
}
});
//Returning all other values as one fields and currenttime as another field
JavaRDD<Tuple2<String,String>> stage2 = filterdata.map(new Function<String, Tuple2<String,String>>() {
public Tuple2<String, String> call(String s) throws ParseException {
String [] entries = s.split(",");
return new Tuple2(s[0]+","+s[2], s[1]);
}
});
List<Tuple2<String,String>> sorted = stage2.takeOrdered(100, new CompareValues()) ;
JavaRDD<Tuple2<String,String>> finale = ctx.parallelize(sorted);
finale.coalesce(1, true).saveAsTextFile("hdfs://localhost:9000/sampleout");
}
}
And my CompareValues.java is shown below
public class CompareValues implements Comparator<Tuple2<String,String>>, Serializable {
#Override
public int compare(Tuple2<String, String> o1, Tuple2<String, String> o2) {
long first = Long.valueOf(o1._2);
long second = Long.valueOf(o2._2);
Date firstDate = new Date(first);
Date secondDate = new Date(second);
return secondDate.compareTo(firstDate);
}
}
when I run this with Name value as argument all are running as expected but the result returns the data in which the first file values are in an ordered manner and then second file values are ordered but I wantthe result in which both file values in an ordered manner
Can anyone help me in this?
I think your problem comes from coalescing your RDD with shuffle=true. This means that the RDD is shuffled using an hash partitioner and each item is sent to the proper partition. Thus, the items are ordered within the partition, but they are not in general. When you save it to a file, each partition is written to a separate file, to allow concurrent writes.
If you want the result to be ordered across all the partitions, you need to set a partitioner which guarantees that all the "close" items are in the same partition.
Look at the Data Partitioning chapter here for further explanations.

How to convert an observableset to an observablelist

I am trying to set items to a tableview but the setitems method expects an observablelist while I have an observableset in my model.The FXCollections utility class does not have a method for creating an observable list given an observable set.I tried casting but that caused a class cast exception (as expected).
Currently I am using this kind of code
new ObservableListWrapper<E>(new ArrayList<E>(pojo.getObservableSet()));
And I have some problems with it:
Will editing this in the table update the underlying set as expected?
Is it the 'right' way of doing this
So in short I need a style guide or best practice for converting between observable set and observable list because I expect to be doing this a lot when building a java fx GUI
Will editing this in the table update the underlying set as expected ?
No because, you are doing a copy of the set:
new ArrayList<E>(pojo.getObservableSet())
Is it the 'right' way of doing this ?
I think the right way is not doing that. Set are not List and vice versa. Both have specific contraints. For example, the lists are ordered and sets contains no duplicate elements.
Moreover, nor FXCollections neither Bindings provides this kind of stuff.
I would like the collection to remain as a set to enforce uniqueness
I guess you could write a custom ObservableList, for example the Parent::children have a similar behavior. It throws an IllegalArgumentException if a duplicate children is added. If you look at the source code, you will see that it is a VetoableListDecorator extension. You could write your own:
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import com.sun.javafx.collections.VetoableListDecorator;
public class CustomObservableList<E> extends VetoableListDecorator<E> {
public CustomObservableList(ObservableList<E> decorated) {
super(decorated);
}
#Override
protected void onProposedChange(List<E> toBeAdded, int... indexes) {
for (E e : toBeAdded) {
if (contains(e)) {
throw new IllegalArgumentException("Duplicament element added");
}
}
}
}
class Test {
public static void main(String[] args) {
Object o1 = new Object();
Object o2 = new Object();
Set<Object> set = new HashSet<Object>();
set.add(o1);
CustomObservableList<Object> list = new CustomObservableList<Object>(FXCollections.observableArrayList(set));
list.add(o2);
list.add(o1); // throw Exception
}
}
Just in Case someone stumbles over this question looking for a one-way to convert an ObservableSet into an ObservableList... I post my solution. It doesn't support feeding back data to the set (which in my opinion wouldn't be nice since TableView doesn't have a concept of not being able to change a value) but supports updates of the set and preserves the (in this case) sorted order.
package de.fluxparticle.lab;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.ObservableSet;
import javafx.collections.SetChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.Collections;
import java.util.Random;
import java.util.TreeSet;
import static javafx.collections.FXCollections.observableSet;
/**
* Created by sreinck on 23.01.17.
*/
public class Set2List extends Application {
private final ObservableSet<Integer> setModel = observableSet(new TreeSet<Integer>());
#Override
public void start(Stage primaryStage) throws Exception {
TableView<Integer> tableView = new TableView<>();
addColumn(tableView, "Number");
ObservableList<Integer> list = convertSetToList(setModel);
tableView.setItems(list);
Random rnd = new Random();
scheduleTask(Duration.millis(1000), () -> setModel.add(rnd.nextInt(10)));
primaryStage.setScene(new Scene(tableView, 800, 600));
primaryStage.setTitle("Set2List");
primaryStage.show();
}
private static void scheduleTask(Duration interval, Runnable task) {
Timeline timeline = new Timeline(new KeyFrame(interval, event -> task.run()));
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
}
private static ObservableList<Integer> convertSetToList(ObservableSet<Integer> set) {
ObservableList<Integer> list = FXCollections.observableArrayList(set);
set.addListener((SetChangeListener<Integer>) change -> {
if (change.wasAdded()) {
Integer added = change.getElementAdded();
int idx = -Collections.binarySearch(list, added)-1;
list.add(idx, added);
} else {
Integer removed = change.getElementRemoved();
int idx = Collections.binarySearch(list, removed);
list.remove(idx);
}
});
return list;
}
private static void addColumn(TableView<Integer> tableView, String text) {
TableColumn<Integer, String> column = new TableColumn<>(text);
column.setCellValueFactory(param -> new SimpleStringProperty(param.getValue().toString()));
tableView.getColumns().add(column);
}
public static void main(String[] args) {
launch(args);
}
}

Categories

Resources