How can I use the 'unique' method in the TotallyLazy library for Java and Objective-C?
I have the following code, but I cannot complete it because I'm not sure how the Callable1 instance passed into 'unique' should be composed. Here's what I have so far:
seq
.sort(new Comparator<T>() {
#Override
public int compare(
final T pt1,
final T pt2
) {
return pt1.compareTo(pt2);
}
})
.unique(new Callable1<T,T>() {
#Override
public T call(final T pt) throws Exception {
final int result = pt.compareTo(..?);
return result != 0;
}});
As you can see, I can sort successfully, but when it comes to "result = ..." in the 'unique' call, what should I put?
Firstly for sorting you should probably use one of the provided Comparators:
seq.sort(Comparators.<T>ascending());
Then you could just unique with no arguments if uniqueness is based on equality of T as a whole. The overload for unique allows one to get a unique sequence based on some property of T.
For example if you had a Sequence<User> you could say I want them to be unique based on their firstName field:
class User {
String firstName, lastName;
User(...){...} // Constructor
}
sequence(new User("Chris", "Nash")).unique(user -> user.firstName)
TotallyLazy has extensive Tests that document the features but the first place to start would always be the SequenceTest or have a look in the whole test package for more examples.
Related
Modifying a local variable in forEach gives a compile error:
Normal
int ordinal = 0;
for (Example s : list) {
s.setOrdinal(ordinal);
ordinal++;
}
With Lambda
int ordinal = 0;
list.forEach(s -> {
s.setOrdinal(ordinal);
ordinal++;
});
Any idea how to resolve this?
Use a wrapper
Any kind of wrapper is good.
With Java 10+, use this construct as it's very easy to setup:
var wrapper = new Object(){ int ordinal = 0; };
list.forEach(s -> {
s.setOrdinal(wrapper.ordinal++);
});
With Java 8+, use either an AtomicInteger:
AtomicInteger ordinal = new AtomicInteger(0);
list.forEach(s -> {
s.setOrdinal(ordinal.getAndIncrement());
});
... or an array:
int[] ordinal = { 0 };
list.forEach(s -> {
s.setOrdinal(ordinal[0]++);
});
Note: be very careful if you use a parallel stream. You might not end up with the expected result. Other solutions like Stuart's might be more adapted for those cases.
For types other than int
Of course, this is still valid for types other than int.
For instance, with Java 10+:
var wrapper = new Object(){ String value = ""; };
list.forEach(s->{
wrapper.value += "blah";
});
Or if you're stuck with Java 8 or 9, use the same kind of construct as we did above, but with an AtomicReference...
AtomicReference<String> value = new AtomicReference<>("");
list.forEach(s -> {
value.set(value.get() + s);
});
... or an array:
String[] value = { "" };
list.forEach(s-> {
value[0] += s;
});
This is fairly close to an XY problem. That is, the question being asked is essentially how to mutate a captured local variable from a lambda. But the actual task at hand is how to number the elements of a list.
In my experience, upward of 80% of the time there is a question of how to mutate a captured local from within a lambda, there's a better way to proceed. Usually this involves reduction, but in this case the technique of running a stream over the list indexes applies well:
IntStream.range(0, list.size())
.forEach(i -> list.get(i).setOrdinal(i));
If you only need to pass the value from the outside into the lambda, and not get it out, you can do it with a regular anonymous class instead of a lambda:
list.forEach(new Consumer<Example>() {
int ordinal = 0;
public void accept(Example s) {
s.setOrdinal(ordinal);
ordinal++;
}
});
As the used variables from outside the lamda have to be (implicitly) final, you have to use something like AtomicInteger or write your own data structure.
See
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#accessing-local-variables.
An alternative to AtomicInteger is to use an array (or any other object able to store a value):
final int ordinal[] = new int[] { 0 };
list.forEach ( s -> s.setOrdinal ( ordinal[ 0 ]++ ) );
But see the Stuart's answer: there might be a better way to deal with your case.
Yes, you can modify local variables from inside lambdas (in the way shown by the other answers), but you should not do it. Lambdas have been made for functional style of programming and this means: No side effects. What you want to do is considered bad style. It is also dangerous in case of parallel streams.
You should either find a solution without side effects or use a traditional for loop.
If you are on Java 10, you can use var for that:
var ordinal = new Object() { int value; };
list.forEach(s -> {
s.setOrdinal(ordinal.value);
ordinal.value++;
});
You can wrap it up to workaround the compiler but please remember that side effects in lambdas are discouraged.
To quote the javadoc
Side-effects in behavioral parameters to stream operations are, in general, discouraged, as they can often lead to unwitting violations of the statelessness requirement
A small number of stream operations, such as forEach() and peek(), can operate only via side-effects; these should be used with care
I had a slightly different problem. Instead of incrementing a local variable in the forEach, I needed to assign an object to the local variable.
I solved this by defining a private inner domain class that wraps both the list I want to iterate over (countryList) and the output I hope to get from that list (foundCountry). Then using Java 8 "forEach", I iterate over the list field, and when the object I want is found, I assign that object to the output field. So this assigns a value to a field of the local variable, not changing the local variable itself. I believe that since the local variable itself is not changed, the compiler doesn't complain. I can then use the value that I captured in the output field, outside of the list.
Domain Object:
public class Country {
private int id;
private String countryName;
public Country(int id, String countryName){
this.id = id;
this.countryName = countryName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
}
Wrapper object:
private class CountryFound{
private final List<Country> countryList;
private Country foundCountry;
public CountryFound(List<Country> countryList, Country foundCountry){
this.countryList = countryList;
this.foundCountry = foundCountry;
}
public List<Country> getCountryList() {
return countryList;
}
public void setCountryList(List<Country> countryList) {
this.countryList = countryList;
}
public Country getFoundCountry() {
return foundCountry;
}
public void setFoundCountry(Country foundCountry) {
this.foundCountry = foundCountry;
}
}
Iterate operation:
int id = 5;
CountryFound countryFound = new CountryFound(countryList, null);
countryFound.getCountryList().forEach(c -> {
if(c.getId() == id){
countryFound.setFoundCountry(c);
}
});
System.out.println("Country found: " + countryFound.getFoundCountry().getCountryName());
You could remove the wrapper class method "setCountryList()" and make the field "countryList" final, but I did not get compilation errors leaving these details as-is.
To have a more general solution, you can write a generic Wrapper class:
public static class Wrapper<T> {
public T obj;
public Wrapper(T obj) { this.obj = obj; }
}
...
Wrapper<Integer> w = new Wrapper<>(0);
this.forEach(s -> {
s.setOrdinal(w.obj);
w.obj++;
});
(this is a variant of the solution given by Almir Campos).
In the specific case this is not a good solution, as Integer is worse than int for your purpose, anyway this solution is more general I think.
I've created a custom udf that is registered but when I try to select custom_udf(10) I get the following error:
Exact implementation of BasicPlatform do not match expected java types
Here is my udf, I can't seem to figure out what is wrong with it:
public class ScalarUdfs {
private ScalarUdfs() {};
#ScalarFunction("basic_platform")
#SqlType(StandardTypes.VARCHAR)
public static Slice BasicPlatform(#SqlNullable #SqlType(StandardTypes.INTEGER) Integer id) {
final Slice IOS = Slices.utf8Slice("iOS");
final Slice ANDROID = Slices.utf8Slice("Android");
final Slice WEB = Slices.utf8Slice("Web");
final Slice OTHER = Slices.utf8Slice("Other");
final Map<Integer, Slice> PLATFORM_MAP = new HashMap<Integer, Slice>() {{
put(20, IOS);
put(42, ANDROID);
put(100, WEB);
}};
if (id == null || !PLATFORM_MAP.containsKey(id)) {
return OTHER;
}
return PLATFORM_MAP.get(id);
}
}
Does anything seem obviously wrong? I want it to return a string given an int as a parameter, and I think the java and sql types match (Integer -> Integer), (Slice -> varchar).
Thanks
The question was also asked and answered on presto-users:
You have to use #SqlNullable #SqlType(StandardTypes.INTEGER) Long id (as SQL integer is backed by Long in Java).
Our team have a shared Java class only for Constant values
When any developer need to add a constant
He will add a record in this class
public class Constants_Class {
public static final String Constant1 = "value1";
public static final String Constant2 = "value2";
public static final String Constant3 = "value3";
// Need to prevent that in Development time - NOT Run time
public static final String Constant4 = "value1"; // value inserted before
}
The problem is that
We need in Development time prevent any developer
To add a new constant its value inserted before
// Need Unique Constants Value(s)
Any suggestions ??
You really should be using enums. This will solve the problem you're seeing.
You can also associate String values with enums:
public enum MyEnums {
Constant1("value1"),
Constant2("value2"),
Constant3("value3");
private String value;
MyEnum(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
}
Then you can do MyEnum.Constant1.getValue().
To do what you're asking at development time would require parsing the code, essentially duplicating compilation. So it makes sense to let it be compiled and create a unit test to perform your check, then set up the project so that unit test is run each time the code base is compiled. I'm pretty sure the most common unit test library in use is JUnit.
To easily check uniqueness of values, you can use the Set.add method, which returns false if the item being added already exists in the set:
#Test
public class TestConstantUniqueness() {
Set<String> stringValues = new HashSet<String>();
for (MyConstantEnum value : MyConstantEnum.values()) {
String s = value.stringValue();
Assert.assertTrue(
"More than one constant in " + MyConstantEnum.class
+ " has the string value \"" + s + "\"",
stringValues.add(s));
}
}
For example:
I got a table like this at UI side:
And this is the list that has all data showed above:
List<MyBean> myList;
Now I want to search by categoryName, languageID or categoryID using a method like this:
private List<MyBean> search(List<MyBean> myList, String columnName, String criteria)
So then I just do the following to get the results that matches my criteria:
1st case: List<Bean> results = this.search(myList, "categoryName", "Dog H");
2nd case: List<Bean> results = this.search(myList, "categoryName", "Dog House");
(At this point results list will return 3 elements in both cases -- according to the above table).
Is it possible to achieve this? As you guys can see, this is a kind of search similar to the %LIKE% function from SQL but focused on java.util.List
Thanks in advance.
I solved my question using the following:
Hamcrest (hamcrest-all-1.3.jar) -- http://hamcrest.googlecode.com/files/hamcrest-all-1.3.jar
Lambdaj (lambdaj-2.4-with-dependencies.jar) -- http://lambdaj.googlecode.com/files/lambdaj-2.4-with-dependencies.jar
Then I just imported the following namespace by this way:
import static ch.lambdaj.Lambda.*;
And get results from my criteria using this:
List<MyBean> results = select(myList, having(on(MyBean.class).getCategoryName(), org.hamcrest.Matchers.containsString("Dog H")));
So, in that line of code I am passing myList, the "column" and criteria as I required in my question.
The rest of code at that line is easy to understand so I won't write about it.
Hope this helps someone else too.
Here's two approaches
The "forceful" approach ;)
public List<MyBean> search(List<MyBean> lstBeans, String method, String regExp) {
List<MyBean> lstMatch = new ArrayList<>(lstBeans.size());
Pattern pattern = Pattern.compile(regExp);
for (MyBean bean : lstBeans) {
if (method.equals("categoryName")) {
String name = bean.getCategoryName();
if (pattern.matcher(name).matches()) {
lstMatch.add(bean);
}
}
}
return lstMatch;
}
.
.
.
List<MyBean> matches = search(lstBeans, "categoryName", "^Dog.*$");
Basically, this relies on knowing that a given method name will return a given result, this would make it difficult to filter results on category, for example...
There are also problems with people misspelling the method name or not taking into account that it's case sensitive...
OR you could try something a little more variable
public interface Criteria<T> {
public boolean matches(T bean);
}
public class CategoryNameCriteria implements Criteria<MyBean> {
private Pattern pattern;
public CategoryCriteria(String criteria) {
pattern = Pattern.compile(criteria);
}
#Override
public boolean matches(MyBean bean) {
return pattern.matcher(bean.getCategoryName()).matches();
}
}
public <T> List<T> search(List<T> lstBeans, Criteria<T> critera) {
List<T> lstMatch = new ArrayList<>(lstBeans.size());
for (T bean : lstBeans) {
if (critera.matches(bean)) {
lstMatch.add(bean);
}
}
return lstMatch;
}
.
.
.
matches = search(lstBeans, new CategoryNameCriteria("^Dog.*$"));
This would allow you to "define" your own criteria and matching requirements without changing the basic method
This would mean you could to develop up a series of criteria independent of the search method, such as
public class CategoryIDCriteria implements Criteria<MyBean> {
private int id;
public CategoryIDCriteria(int id) {
this.id = id;
}
#Override
public boolean matches(MyBean bean) {
return bean.getCategoryID() == id;
}
}
.
.
.
matches = search(lstBeans, new CategoryIDCriteria(1));
And because the criteria and search method are generic, it would be possible to reuse it with different types of objects
If you are willing to use third party libraries, perhaps JoSQL will suffice? It allows you to filter collections of POJOs using SQL queries...
Also, if you are willing to move away from SQL queries, this old post may be of interest: How do you query object collections in Java (Criteria/SQL-like)?
Instead of a List, why not use Guava's Table?
Table<Integer, Integer, String> table = HashBasedTable.create();
table.put(1, 1, "Advantage Flea");
table.put(1, 2, "Advantage Flea");
table.put(1, 3, "Advantage Flea");
.
.
.
Case #1 requires something like:
Collection<String> values = table.values();
for(String value : values) {
if(value.contains(queryString) {
//found it!
}
}
Case #2 is trivial, and just looks like:
if(table.containsValue("Advantage Flea") {
...
}
I have some enums like this:
public enum Classification {
UNKNOWN("Unknown"),
DELETION("Deletion"),
DUPLICATION("Duplication"), ....
but some of them have like 20 members, so currently in code I deal with them with huge if/else blocks like this:
int classification= rs.getInt("classification");
if (classification == Classification.UNKNOWN.ordinal()) {
variant.setClassification(Classification.UNKNOWN);
} else if (classification == Classification.DELETION.ordinal()) {
variant.setClassification(Classification.DELETION);
( rs is from JDBC tho).
Does Java have a better way this these big if/else blocks to do what I am doing? some sorting of looping through it?
You could use Enum#values() to get all enum values in an array. The ordinal maps 1:1 to the array index. Add the following method fo your Classification enum:
public static Classification of(int ordinal) {
if (0 <= ordinal && ordinal < values().length) {
return values()[ordinal];
}
throw new IllegalArgumentException("Invalid ordinal " + ordinal);
}
and use it as follows
Classification classification = Classification.of(rs.getInt("classification"));
// ...
However, using enum's ordinal for this is not the best practice. What if some developer rearranges the enum's values or adds/removes values? Even the javadoc warns that it has usually no use for developers. Rather give each enum value a fixed identifier. You could pass it in as an additional argument of the enum constructor argument. You could even use enum's String representation for that.
UNKNOWN(1, "Unknown"),
DELETION(2, "Deletion"),
DUPLICATION(3, "Duplication"),
// ...
Then use that value for DB instead and modify the of() method to walk through them in a foreach loop:
public static Classification of(int id) {
for (Classification classification : values()) {
if (classification.id == id) {
return classification;
}
}
throw new IllegalArgumentException("Invalid id " + id);
}
If the db value is the ordinal of the Enum then:
int classification= rs.getInt("classification");
variant.setClassification(Classification.values()[classification]);
I'll leave bounds checking as an exercise for the reader.
You can loop through an enumeration’s values via the object the someEnum.values() method returns:
for (Classification clz : Classification.values()) doSomethingWith(clz);
found here
I don’t know how exactly I can help you, since i don’t know what rs.getInt(String) does.
It seems to give back an Integer representing a enum value of Classification, but why?
Use variant.setClassification(YourEnumClassHere.values()[classification]). Enum.values() returns an array of all the declared enums in that class.
Instead of storing ordinal, you can store the name and use the valueOf method to convert the String back to your Enum type.
If you willing and able to store a string representation (this is a good technique) of the ENUM in your database, see Reference from Gareth Davis in comments above. If you are unwilling and/or unable to store a string representation and must continue with an ordinal representation, I suggest that a Map is called for. Here is some example code:
public class EnumMap
{
private enum FistSounds
{
Blam, Kapow, Zowie, Biff;
private static Map<Integer, FistSounds> ordinalMap = new HashMap<Integer, FistSounds>();
static
{
ordinalMap.put(Blam.ordinal(), Blam);
ordinalMap.put(Kapow.ordinal(), Kapow);
ordinalMap.put(Zowie.ordinal(), Zowie);
ordinalMap.put(Biff.ordinal(), Biff);
}
public static final FistSounds getByOrdinal(final int enumIndex)
{
return ordinalMap.get(enumIndex);
}
}
public static void main(String[] args)
{
FistSounds fistSound;
for (int index = -1; index < 5; ++index)
{
fistSound = FistSounds.getByOrdinal(index);
System.out.print("Ordinal: ");
System.out.print(index);
System.out.print(", FistSound: ");
System.out.println(fistSound);
}
}
}
I'd recommend using a switch statement, if the logic to execute is different for each case....
do as #Gareth Davis instructs and then just have a switch statement and handle each case as required.
Enums are also eligible to be used in switch statements see here