Java passing a (lambda) function with two arguments - java

I'm trying to implement a function to read files, but I cannot change the signature of the method. There are a lot of cross references in the code but maybe someone can enlighten me, I have been stuck for 3 days right now. This is for a school assignment.
The first method I'm trying to pass into the function is the following:
public static Purchase fromLine(String textLine, List<Product> products) {
Purchase newPurchase = null;
String[] purchases = textLine.split(",");
int foundBarcode = products.indexOf(getProductFromBarcode(products, Long.parseLong(purchases[0])));
products.indexOf(purchases);
newPurchase = new Purchase(
products.get(foundBarcode),
Integer.parseInt(purchases[1].trim())
);
Somehow I want to pass this function into my import file function.
public static <E> void importItemsFromFile(List<E> items, String filePath, Function<String,E> converter) {
int originalNumItems = items.size();
Scanner scanner = createFileScanner(filePath);
// TODO read all source lines from the scanner,
// convert each line to an item of type E and
// and add each item to the list
while (scanner.hasNext()) {
// input another line with author information
String line = scanner.nextLine();
// TODO convert the line to an instance of E
E newItem = converter.apply(line);
// TODO add the item to the list of items
items.add(newItem);
}
System.out.printf("Imported %d items from %s.\n", items.size() - originalNumItems, filePath);
}
I hope someone can help me and explain how to pass this function into the other function's converter parameter.
Tried to do a lot of research on this topic but I'm still not able to find the answer. Please help me stackoverflow community!:D

You need to declare this like this first inside a 'super - private function'
private Function<String, Purchase> doSomething() {
return textLine -> {
Purchase newPurchase = null;
String[] purchases = textLine.split(",");
int foundBarcode = products.indexOf(getProductFromBarcode(products, Long.parseLong(purchases[0])));
products.indexOf(purchases);
return new Purchase(products.get(foundBarcode), Integer.parseInt(purchases[1].trim())
};
}
Then before calling this importItemsFromFile() method, you declare this function as a variable
Function<String, Purchase> abcFunction = doSomething();
and then call this importItemsFromFile() function like this
importItemsFromFile(items, filePath, abcFunction);
The reason why this works is, lambda operator returns a Functional Interface, here it is "Function", if you pass 3 arguments, you will need a BiFunction<T, U, R> for that.
Thats why these FunctionalInterfaces are sometimes called super private functions, as they are used inside another function.
And Hey give me extra points for this, as I even completed your half written function, and saved your 3 days time.

I am a little lost by the top snippet, but all you need to do is define an implementation of the Function interface. You can do this simply by defining a class that implements the interface or you can specify a lambda that would do the same thing.
Assuming the top code block is what you want in your lambda you would do something like this,
(textLine) ->{
String[] purchases = textLine.split(",");
int foundBarcode = products.indexOf(getProductFromBarcode(
products, Long.parseLong(purchases[0])));
products.indexOf(purchases);
return new Purchase(
products.get(foundBarcode),
Integer.parseInt(purchases[1].trim())
)

Related

Removing an input from a recursive method

Good morning! I received a problem statement to write a method that returns all possible combinations of a String input passed, e.g.
if ABC is passed then it returns [A, AB, BC, ABC, AC, B, C]
if ABCD is passed then it returns [A, AB, BC, CD, ABC, AC, ACD, B, BCD, BD, ABD, AD, C, D, ABCD]
means AB and BA are always taken same, ABC, BAC and ACB are also same.
I ended up writing below code and it seems to working though (not sure).
public static Set<String> getAnyPermutations(String s,String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for(int i=0; i<inp.length; i++) {
String temp =s+String.valueOf(inp[i]);
resultSet.add(temp);
if(i+1<=inp.length)
resultSet.addAll(getAnyPermutations(temp, String.valueOf(Arrays.copyOfRange(inp, i+1, inp.length))));
}
return resultSet;
}
My question is, I want to remove the first param(String s) from the method as using it for interal comutations only, or if that is not possible then making sure that user always pass a "" value or I can reset it to "" for the first(non-recursive) call of this method. I am going confused how to do that inside a recursive funtion.
Also please add comment if you have doubt it can fail other than this situation.
Conditions, All has to be done inside this function only, no other method can be created.
All has to be done inside this function only, no other function can be created.
Then you can't do it. The function has no (reasonable)* way of knowing whether it called itself or was called by another function.
There are lots of solutions involving creating another function. One that might fit your requirements, depending on how they're actually expressed, would be to have the function define a lambda to do the work, and have the lambda call itself. E.g., getAnyPermutations wouldn't actually be recursive, it would contain a recursive function.
But that may be out of bounds depending on the exact meaning of the quote above, since the lambda is another function, just not one that can be accessed from the outside.
* The unreasonable way is by examining a stack trace, which you can get from Thread.currentThread().getStackTrace.
You can always transform a recursive method into its iterative equivalent - e.g. see
Way to go from recursion to iteration.
In the iterative version it's easy to not expose the state parameter (you now just need to initialize it at the beginning of the iterative method).
This is not very practical in general (but I believe that the purpose of the question is more theoretical, otherwise it's always a good solution to just expose another method).
Furthermore, in this particular situation you might consider this simple iterative approach (though it is not obtained by directly translating the given code):
public static Set<String> getAnyPermutations(String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for (int bitMask = 0; bitMask < (1 << inp.length); bitMask++) {
StringBuilder str = new StringBuilder();
for (int i = 0; i < inp.length; i++) {
if ((bitMask & (1 << i)) != 0) {
str.append(inp[i]);
}
}
if (str.length() > 0) {
resultSet.add(str.toString());
}
}
return resultSet;
}
You can change the current method to be a private one and interface it with a public method with one argument e.g.:
private static Set<String> getAnyPermutations(String s,String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for(int i=0; i<inp.length; i++){
String temp =s+String.valueOf(inp[i]);
resultSet.add(temp);
if(i+1<=inp.length)
resultSet.addAll(getAnyPermutations(temp, String.valueOf(Arrays.copyOfRange(inp, i+1, inp.length))));
}
return resultSet;
}
Now, you can expose a one argument method to the user which in turn will call the above method, e.g.:
public static Set<String> getAnyPermutations(String strInput) {
return getAnyPermutations("", strInput);
}
Update
If you can't create any other method at all then the only alternative would be to use var-args. However, that requires change in the implementation and doesn't actually restrict the user from passing multiple values.
You can rewrite this particular algorithm so that it doesn't need to carry a state through to the recursively called invocation.
(Java-centric pseudocode):
Set<String> getAnyPermutations(String str) {
if(str.length() == 0) {
return Collections.emptySet();
}
String head = str.substring(0,1);
String tail = str.substring(1);
Set<String> permutationsOfTail = getAnyPermutations(tail);
Set<String> result = new HashSet();
// Head on its own
// For input 'ABC', adds 'A'
result.add(head);
// All permutations that do not contain head
// For input 'ABC', adds 'B', 'C', 'BC'
result.addAll(permutationsOfTail);
// All permutations that contain head along with some other elements
// For input 'ABC', adds 'AB, 'AC', 'ABC'
for(String tailPerm : permutationsOfTail) {
result.add(head + tailPerm);
}
return result;
}
This meets your aim of not creating any extra methods -- but note that it would be cleaner code if the for loop was extracted into a new method Set<String> prefixEachMember(String prefix, Set<String> strings) allowing result.addAll(prefixEachMember(head,permutationsOfTail)).
However it's not always possible to do this, and sometimes you do want to carry state. One way is the way you've asked to avoid, but I'm going to include it in my answer because it's a clean and common way of achieving the aim.
public Foo myMethod(Bar input) {
return myMethod(new HashSet<Baz>(), input);
}
private Foo myMethod(Set<Baz> state, Bar input) {
if(...) {
return ...;
} else {
...
return myMethod(..., ...);
}
}
Here, the first method is your public API, in which the collector/state parameter is not required. The second method is a private worker method, which you initially call with an empty state object.
Another option is to refer to an object field. I would recommend against this, however, because it gets confusing when recursive code refers to a global object.

What input should I put in method call in blue j?

This is for the assignmet for the course Principle of Software Design on Coursera. When I try to run the void sortbylargestdepth method, I am prompted to put some input in the function call method. What input should I put there to run the method? Is this what suppose to happen or did I make a mistake in writing code? Below I have included the code as well as the screenshot of the problem: Hope to get a reply soon.
Here is the code for the method:
public void sortByLargestDepth(ArrayList<QuakeEntry> in) {
for (int i=0; i< 50; i++) {
int minIdx = getLargestDepth(in,i);
QuakeEntry qi = in.get(i);
QuakeEntry qmin = in.get(minIdx);
in.set(i,qmin);
in.set(minIdx,qi);
}
The method should have the signature changed to:
public void sortByLargestDepth(ArrayList<QuakeEntry> quakeEntries)
As the method is expecting an ArrayList<QuakeEntry (list of QuakeEntry's)
So you need to create a list and pass it in to the method call if one is not already provided.
Because we don't have the code for QuakeEntry, I will assume there is a default no-arg constructor. It would look something like:
ArrayList<QuakeEntry> entries = new ArrayList<>();
QuakeEntry entry1 = new QuakeEntry();
//Init entry 1 here
QuakeEntry entry2 = new QuakeEntry();
//Init entry 2 here (or better yet have a constructor that allows you to init
sortByLargestDepth(entries);

ArrayList getting reinitialized everytime the method is called

I have written a method (part of a program) which takes in two int values(code below). One int value representing number of guys for whom java training is completed and another int value for guys for whom php training is completed. I expect the arraylist to grow with every function call. Example: First time I called the function with values (5,0). So the arrayList for java would be [5] and for php it would be [0] . Next time I call the function with values (2,3). The arrayList for java should now be [5][2] and sum should be 7. The the arraylist for php should be [0][3] ans sum should be 3. The problem with my code is that when I call the method for the second time, it wipes away the [5](value of first index from the first call) in the java arrayList and just takes the form of [2] and gives the sum 2(instead of the required 7). The arrayList is never growing. (same for the php arrayList) I am sure I am doing something conceptually wrong here . Please help Somehow, the way I have coded it, every function call seems to make a new arrayList and not growing the arrayList obtained from the previous call.
public class TrainingCamp {
public static int trainedJavaGuys ;
public static int trainedPHPGuys ;
public void trainedTroopsInCamp(int java,int php){
//System.out.println("********* Current Status of Training Camp ********* ");
ArrayList<Integer> trainingListJava = new ArrayList<>();
trainingListJava.add(java);
//System.out.println("---JavaARRAYLIST----"+trainingListJava);
trainedJavaGuys = sumList(trainingListJava);
ArrayList<Integer> trainingListPHP = new ArrayList<>();
trainingListPHP.add(php);
trainedPHPGuys = sumList(trainingListPHP);
//System.out.println("---phpARRAYLIST----"+trainingListPHP);
Calling it like this from another class:
TrainingCamp currentTrainingCamp = new TrainingCamp();
currentTrainingCamp.trainedTroopsInCamp(2, 0);
and next time the same two lines get executed with just the input params changed
The arraylists are reinitialized each time you call trainedTroopsInCamp() because they are declared within it.
You should make the arraylists member variables, so that they only get initialized once, in the class's constructor.
public class TrainingCamp {
public static int trainedJavaGuys ;
public static int trainedPHPGuys ;
// Declare once
ArrayList<Integer> trainingListJava;
ArrayList<Integer> trainingListPHP;
public TrainingCamp() {
// Initialize once
trainingListJava = new ArrayList<>();
trainingListPHP = new ArrayList<>();
}
public void trainedTroopsInCamp(int java,int php){
// Use everywhere
trainingListJava.add(java);
trainedJavaGuys = sumList(trainingListJava);
trainingListPHP.add(php);
trainedPHPGuys = sumList(trainingListPHP);
}
}
you're re-initializing the list references in the method call, so every time you call the method you're using a new (empty) list.
instead, try keeping the lists as member variables for your class, something like this:
class TrainingCamp {
private final List<Integer> javaTrained = new LinkedList<>();
private final List<Integer> phpTrained = new LinkedList<>();
public void trainedTroopsInCamp(int java,int php){
//System.out.println("********* Current Status of Training Camp ********* ");
javaTrained.add(java);
trainedJavaGuys = sumList(javaTrained);
phpTrained.add(php);
trainedPHPGuys = sumList(phpTrained);
}
...
}

How to access methods that takes array as argument,without argument?(java)

im quite a beginner in Java and im facing a problem with my code.Bascially I have a class containing a method that create a listarray based on user input:
public class manage{
public void adding() {
boolean loop = true;
ArrayList<Game> thegame = new ArrayList<Game>();
while(loop) {
Scanner agame = new Scanner(System.in);
System.out.print("name: \n");
String Cgame = agame.nextLine();
Scanner qty = new Scanner(System.in);
System.out.print("the qty: \n");
int CQty = qty.nextInt();
Console wertgame = new Console(Cgame,Cqty);
thegame.add(new Game(Cgame,Cqty));
System.out.println("continue?");
Scanner autre = new Scanner(System.in);
int continu = other.nextInt();
if(continu==1) {
}
else if(continu==2) {
Main.menu();
}
}
return thegame;
}
And then I have another method in the same class that is to display it:
public void information(List<Game> thegame) {
System.out.print(thegame);
}}
The problem im having here, is that I need to access the information(List thegame) method, from another class(java file).However,how do I access it from my other class since I cant access(call) it using "manage.information()"since it needs argument,but my arraylist isnt created yet in my other class,it gets create only when in the manage class.So I cant pass the arguments when calling it.How do I access/call it from my other class then?
thank you
The simple answer is that you can't.
If you want to call a method that requires an argument, then you need to pass that argument in some form or another.
IMO, the best solution would simply be to not call the information method at the point where you don't have the argument it requires. The sole purpose of the method seems to be to print out its argument, so if you don't have an object (list) to print then the method call cannot do anything worthwhile.
Alternatively, you could pass a null instead of a list, but that will simply result in the method outputting "null" which seems rather pointless.
In short, you can't pass an argument that doesn't exist. It simply makes no sense. Think again about what you are actually trying to do here.

Delete object from array

I've got this constructor in the class Music:
protected String Title;
protected String Autor;
protected String Type;
protected int Code;
public Music (String title, String autor, String type, int code){
this.setTitle(title);
this.setAutor(autor);
this.setType(type);
this.setCode(code);
}
#Override
public String toString(){
return this.Title + " " + this.Autor + " " + this.Type + " " + this.Code;
}
Then, in other class called ManageMusic I create some methods to then use them on the main class. I also define a String array refered to the Music class which I will use in the main class:
private final Music[] musicList;
private int counter;
public ManageMusic(int maxSize) {
musicList= new Music[maxSize];
counter= 0;
public void add(Music m){
musicList[counter] = m;
counter++;
}
Here, I have to create a delete method which would delete a especific object from the musicList and return this list without that object.
This is the way I add music elements to the musicList on the main class:
static ManageMusic musiclist = new ManageMusic(20);
musicList.add(new Music(title, autor, format, code));
My approach for the delete method in the ManageMusic class is to copy this list into a new String[] and then copy it back to the list. But as I'm using an objet from Music instead of from String, I cannot make the copy back because it does not cast the String to the musicList:
public void delete(int code){
String[] newString = new String[musicList.length];
int index_1 = 0;
for (int i=0; i<musicList.length; i++){
if(i != code){
newString[index_1] = musicList[i].toString();
index_1++;
}
}
int index_2 = 0;
for (int i=0; i<newString.length; i++){ //THIS IS WHERE IT SAYS: Cannot convert
// from String to Music
musicList[index_2] = newString[i];
index_2++;
}
}
I have to do something not far from this, because then I've got a method that list elements from the musicList, so I cannot set a return statement for the method.
Why you can do it without an ArrayList
As some people suggested in the comments, you should probably use ArrayLists or similar stuff from the java.util.collection package.
However I assume you want to learn how such things work, so I will not provide you with code (First because I'm too lazy, second to encourage you to learn it yourself) but with some explanation.
edit: First: Your problem is that you copy strings, not references. Instead of trying to use the toString method, try to handle it with the "objects" (i.e. their references) themselves.
Error checking
As you might have noticed your add will cause an IndexOutOfBoundsException if you try to add another entry after your list reached your max_size. You should check for that. You should also check lots of things in the following explanations, I'll provide a few suggestions.
Simple deletion with your exact example
Just use Music[] instead of String[] and copy the reference of the temp Music[] to your musicList.
Better way to handle it: dynamic array structure
So what I suggest is to make use of a dynamic array structure. You will have to copy arrays around a lot, which can be a bit difficult. But basically it's what an ArrayList does.
Constructor
But how to implement that dynamic structure? Let's first start with the initialization, i.e. your constructor. You will not need a parameter for a maximum size (unless you want to restrict your music collection for some reason). Just create an array with size 0. (Of course you can also implement copy constructors and other things, but for the start keep it simple.)
add()
To add more music, you simply create a new array with the size of your current collection + 1, copy all references (this is probably the answer you were looking for. You take the strings, but just take the objects themselves) from the current array to the new array, add the new Music and change the reference of your member variable to your newly created, bigger array (i.e. assigning musicList = tempArray; or something similar). (Error checking: is the object null?)
delete()
For deletion you can do just the same. Create a new temporary array (this time with a reduced size), copy all values over but leave out the one you want to delete. To determine which shall be deleted you can either check for indices or even check the objects for equality. (Error checking: size of temp array should never be smaller than 1, so check if your array is empty - consider to use a method like isEmpty() for that.)
Why should I do this?
Once you got those concepts you will be able to manage your array in whatever way you like. Search through it, delete all elements, copy your music collection to your friend's, etc. etc.
And beyond that?
And after you learned this, go ahead and try the ArrayList - you will figure out it works very much like what you have just written. And now you can be proud that you not only can use ArrayLists, but also know how and why they behave like they do.
Its better to use ArrayList than writing own logic to delete object from existing array. Here is how you can use ArrayList :
{
ArrayList<Music> list = new ArrayList<Music>();
Music m1 = new Music(title, autor, format, code);
list.add(m1);
// similarly you can check whether object is present in ArrayList or not using
if(list.contains(m1)){ // This check whether object is present in ArrayList or not
//Do whatever you want
}
}
ArrayList example:
List<Music> musicList = new ArrayList<Music>();
adding to end of list list:
musicList.add(new Music(...));
adding to specified position in list (later ones all move up one place)
musicList.add(index, new Music(..));
remove from list:
musicList.remove(index);
or
musicList.remove(someMusic);
Size of list:
int size = musicList.size();
Get first music:
Music first = musicList.get(0);
Get last music:
Music last = musicList.get(musicList.size()-1);
Loop:
for (Music : musicList) {
//do stuff
}
do like this
public void delete(int code){
List<Music> list = new ArrayList<Music>(); //creating new empty list
for (Music m:musicList){
if(m.code != code){ // removing condition
list.add(m); // adding music to new list
}
}
musicList = list.toArray(new Music[list.size()]); // assigning back list to musicList
}

Categories