Java stream, how to apply a function to the previous result - java

I was looking for a right answer, but found nothing that fill my purpose.
I have a simple for loop like this:
String test = "hi";
for(Something something : somethingList) {
if(something.getSomething() != null) {
test = cleaner.clean(test, something.getSomething());
} else if(something.getOther() != null) {
test = StaticClass.clean(test, something.getOther());
}
}
and I never understood if the same result can be achieved using java stream. With reduce maybe? I need to pass the response of the previuos loop (saved in the "test" variable) to the next loop (see clean method, where I pass test). How can I do that?

If you want to do something for each element in a list (with a for each loop) I would suggest using the forEach or forEachOrdered functions. These should represent your for(Object o : objects). You can easily define your own Consumer class, which handles all the stuff for you:
class CustomConsumer implements Consumer<Integer> {
private Integer previous;
public CustomConsumer(Integer initialValue) {
previous = initialValue;
}
#Override
public void accept(Integer current) {
// do stuff with your current / previous object :)
System.out.println("previous: " + previous);
previous = current;
}
}
List<Integer> values = getValues();
values.stream()
.forEachOrdered(new CustomConsumer(-1));
This example uses Integer as a provided class, if you want to use your own just replace Integer. You can even use generics:
class CustomConsumer<T> implements Consumer<T> {
private T previous;
public CustomConsumer(T initialValue) {
previous = initialValue;
}
#Override
public void accept(T current) {
// do stuff with your current / previous object :)
System.out.println("previous: " + previous);
previous = current;
}
}
List<Integer> values = new ArrayList<>();
for(int i = 0; i < 6; i++)
values.add(i);
values.stream()
.forEachOrdered(new CustomConsumer<>("hello"));
Output:
previous: hello
previous: 0
previous: 1
previous: 2
previous: 3
previous: 4
If you want to learn more about streams the oracle docs provide some good stuff.

To expand on my comment, with streams you basically could use reduction, e.g. by using the reduce() method.
Example:
//some list simulating your somethingList
List<Integer> list = List.of(2,4,6,1,3,5);
String result = list.stream()
//make sure the stream is sequential to keep processing order
.sequential()
//start reduction with an initial value
.reduce("initial",
//in the accumulator you get the previous reduction result and the current element
(test, element) -> {
//simulates your conditions, just adding the new element for demonstration purposes
// test could also be replaced
if( element % 2 == 0 ) {
test += ", even:" + element;
} else {
test += ", odd: " + element;
}
//return the new reduction result
return test;
},
//combiner is not used in sequential streams so just one of the elements
(l, r) -> l);
This would result in:
initial, even:2, even:4, even:6, odd: 1, odd: 3, odd: 5
Note, however, that streams are not a silver bullet and sometimes a simple loop like your initial code is just fine or even better. This seems to be such a case.

Related

How to combine (append) generic Lists in Java without using Javas Collection Framework?

is there an efficient way to combine two generic doube linked lists without using the Collection Framework of Java? The lists are already sorted, so it is only necessary to append the second list to the first one. So far I tried this way, but I am not sure if this is the correct approach:
public void combineWith(List<T> anotherList) {
DoubleLinkedList<T> list1 = new DoubleLinkedList<>();
anotherList = new DoubleLinkedList<>();
list1= this;
if(this.next==null) {
list1.next= (DoubleLinkedList<T>) anotherList;
}
Thanks in advance.
Intended is a merge of sorted lists. For walking with insert/remove, the Iterator or in this case ListIterator is useful. A double linked list could also move by pointers in the lists.
The basic algorithm is:
/**
* Merge this list with another, both are sorted.
* #param other unchanged list.
*/
public void mergeSorted(List<T> other) {
Iterator<T> iter = iterator();
Iterator<T> otherIter = other.iterator();
while (iter.hasNext() && otherIter.hasNext()) {
T value = iter.next();
T otherValue = otherIter.next();
int cmp = value.compareTo(otherValue);
if (cmp >= 0) {
if (cmp > 0) {
iter.insert(otherValue);
}
otherIter.next();
}
if (cmp <= 0) {
iter.next();
}
}
while (other.hasNext()) {
iter.insert(other.next());
}
}
Here I skip on equal elements.
My attempt at ascii art:
Equal (this, other)
: :
X = X
| |
Less
: :
X :
: \ :
: Y
| :
Greater
: :
: X
: / :
Y +
: |
Try the Method I posted below. Obviously this only works if it is placed within the class DoubleLinkedList, which I assume it is, since you set list1 = this which would only be possible if this already is a DoubleLinkedList.
first is the first element (or node) of the DoubleLinkedList and last is the last element (or node) of the DoubleLinkedList. If you don't have those saved as a global variable, I'd either do so or implement another method to find the first and last element.
public void combineWith(DoubleLinkedList<T> anotherList) {
if(anotherList.isEmpty()) return;
if(this.isEmpty()){
this = anotherList;
return;
}
this.last.next = anotherList.first;
anotherList.first.previous = this.last;
}

How to match the exact string value in the list of comma separated string [duplicate]

I have a String[] with values like so:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Given String s, is there a good way of testing whether VALUES contains s?
Arrays.asList(yourArray).contains(yourValue)
Warning: this doesn't work for arrays of primitives (see the comments).
Since java-8 you can now use Streams.
String[] values = {"AB","BC","CD","AE"};
boolean contains = Arrays.stream(values).anyMatch("s"::equals);
To check whether an array of int, double or long contains a value use IntStream, DoubleStream or LongStream respectively.
Example
int[] a = {1,2,3,4};
boolean contains = IntStream.of(a).anyMatch(x -> x == 4);
Concise update for Java SE 9
Reference arrays are bad. For this case we are after a set. Since Java SE 9 we have Set.of.
private static final Set<String> VALUES = Set.of(
"AB","BC","CD","AE"
);
"Given String s, is there a good way of testing whether VALUES contains s?"
VALUES.contains(s)
O(1).
The right type, immutable, O(1) and concise. Beautiful.*
Original answer details
Just to clear the code up to start with. We have (corrected):
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
This is a mutable static which FindBugs will tell you is very naughty. Do not modify statics and do not allow other code to do so also. At an absolute minimum, the field should be private:
private static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
(Note, you can actually drop the new String[]; bit.)
Reference arrays are still bad and we want a set:
private static final Set<String> VALUES = new HashSet<String>(Arrays.asList(
new String[] {"AB","BC","CD","AE"}
));
(Paranoid people, such as myself, may feel more at ease if this was wrapped in Collections.unmodifiableSet - it could then even be made public.)
(*To be a little more on brand, the collections API is predictably still missing immutable collection types and the syntax is still far too verbose, for my tastes.)
You can use ArrayUtils.contains from Apache Commons Lang
public static boolean contains(Object[] array, Object objectToFind)
Note that this method returns false if the passed array is null.
There are also methods available for primitive arrays of all kinds.
Example:
String[] fieldsToInclude = { "id", "name", "location" };
if ( ArrayUtils.contains( fieldsToInclude, "id" ) ) {
// Do some stuff.
}
Just simply implement it by hand:
public static <T> boolean contains(final T[] array, final T v) {
for (final T e : array)
if (e == v || v != null && v.equals(e))
return true;
return false;
}
Improvement:
The v != null condition is constant inside the method. It always evaluates to the same Boolean value during the method call. So if the input array is big, it is more efficient to evaluate this condition only once, and we can use a simplified/faster condition inside the for loop based on the result. The improved contains() method:
public static <T> boolean contains2(final T[] array, final T v) {
if (v == null) {
for (final T e : array)
if (e == null)
return true;
}
else {
for (final T e : array)
if (e == v || v.equals(e))
return true;
}
return false;
}
Four Different Ways to Check If an Array Contains a Value
Using List:
public static boolean useList(String[] arr, String targetValue) {
return Arrays.asList(arr).contains(targetValue);
}
Using Set:
public static boolean useSet(String[] arr, String targetValue) {
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
}
Using a simple loop:
public static boolean useLoop(String[] arr, String targetValue) {
for (String s: arr) {
if (s.equals(targetValue))
return true;
}
return false;
}
Using Arrays.binarySearch():
The code below is wrong, it is listed here for completeness. binarySearch() can ONLY be used on sorted arrays. You will find the result is weird below. This is the best option when array is sorted.
public static boolean binarySearch(String[] arr, String targetValue) {
return Arrays.binarySearch(arr, targetValue) >= 0;
}
Quick Example:
String testValue="test";
String newValueNotInList="newValue";
String[] valueArray = { "this", "is", "java" , "test" };
Arrays.asList(valueArray).contains(testValue); // returns true
Arrays.asList(valueArray).contains(newValueNotInList); // returns false
If the array is not sorted, you will have to iterate over everything and make a call to equals on each.
If the array is sorted, you can do a binary search, there's one in the Arrays class.
Generally speaking, if you are going to do a lot of membership checks, you may want to store everything in a Set, not in an array.
For what it's worth I ran a test comparing the 3 suggestions for speed. I generated random integers, converted them to a String and added them to an array. I then searched for the highest possible number/string, which would be a worst case scenario for the asList().contains().
When using a 10K array size the results were:
Sort & Search : 15
Binary Search : 0
asList.contains : 0
When using a 100K array the results were:
Sort & Search : 156
Binary Search : 0
asList.contains : 32
So if the array is created in sorted order the binary search is the fastest, otherwise the asList().contains would be the way to go. If you have many searches, then it may be worthwhile to sort the array so you can use the binary search. It all depends on your application.
I would think those are the results most people would expect. Here is the test code:
import java.util.*;
public class Test {
public static void main(String args[]) {
long start = 0;
int size = 100000;
String[] strings = new String[size];
Random random = new Random();
for (int i = 0; i < size; i++)
strings[i] = "" + random.nextInt(size);
start = System.currentTimeMillis();
Arrays.sort(strings);
System.out.println(Arrays.binarySearch(strings, "" + (size - 1)));
System.out.println("Sort & Search : "
+ (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
System.out.println(Arrays.binarySearch(strings, "" + (size - 1)));
System.out.println("Search : "
+ (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
System.out.println(Arrays.asList(strings).contains("" + (size - 1)));
System.out.println("Contains : "
+ (System.currentTimeMillis() - start));
}
}
Instead of using the quick array initialisation syntax too, you could just initialise it as a List straight away in a similar manner using the Arrays.asList method, e.g.:
public static final List<String> STRINGS = Arrays.asList("firstString", "secondString" ...., "lastString");
Then you can do (like above):
STRINGS.contains("the string you want to find");
With Java 8 you can create a stream and check if any entries in the stream matches "s":
String[] values = {"AB","BC","CD","AE"};
boolean sInArray = Arrays.stream(values).anyMatch("s"::equals);
Or as a generic method:
public static <T> boolean arrayContains(T[] array, T value) {
return Arrays.stream(array).anyMatch(value::equals);
}
You can use the Arrays class to perform a binary search for the value. If your array is not sorted, you will have to use the sort functions in the same class to sort the array, then search through it.
ObStupidAnswer (but I think there's a lesson in here somewhere):
enum Values {
AB, BC, CD, AE
}
try {
Values.valueOf(s);
return true;
} catch (IllegalArgumentException exc) {
return false;
}
Actually, if you use HashSet<String> as Tom Hawtin proposed you don't need to worry about sorting, and your speed is the same as with binary search on a presorted array, probably even faster.
It all depends on how your code is set up, obviously, but from where I stand, the order would be:
On an unsorted array:
HashSet
asList
sort & binary
On a sorted array:
HashSet
Binary
asList
So either way, HashSet for the win.
Developers often do:
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
The above code works, but there is no need to convert a list to set first. Converting a list to a set requires extra time. It can as simple as:
Arrays.asList(arr).contains(targetValue);
or
for (String s : arr) {
if (s.equals(targetValue))
return true;
}
return false;
The first one is more readable than the second one.
If you have the google collections library, Tom's answer can be simplified a lot by using ImmutableSet (http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ImmutableSet.html)
This really removes a lot of clutter from the initialization proposed
private static final Set<String> VALUES = ImmutableSet.of("AB","BC","CD","AE");
In Java 8 use Streams.
List<String> myList =
Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList.stream()
.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
One possible solution:
import java.util.Arrays;
import java.util.List;
public class ArrayContainsElement {
public static final List<String> VALUES = Arrays.asList("AB", "BC", "CD", "AE");
public static void main(String args[]) {
if (VALUES.contains("AB")) {
System.out.println("Contains");
} else {
System.out.println("Not contains");
}
}
}
Using a simple loop is the most efficient way of doing this.
boolean useLoop(String[] arr, String targetValue) {
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
}
Courtesy to Programcreek
the shortest solution
the array VALUES may contain duplicates
since Java 9
List.of(VALUES).contains(s);
Use the following (the contains() method is ArrayUtils.in() in this code):
ObjectUtils.java
public class ObjectUtils {
/**
* A null safe method to detect if two objects are equal.
* #param object1
* #param object2
* #return true if either both objects are null, or equal, else returns false.
*/
public static boolean equals(Object object1, Object object2) {
return object1 == null ? object2 == null : object1.equals(object2);
}
}
ArrayUtils.java
public class ArrayUtils {
/**
* Find the index of of an object is in given array,
* starting from given inclusive index.
* #param ts Array to be searched in.
* #param t Object to be searched.
* #param start The index from where the search must start.
* #return Index of the given object in the array if it is there, else -1.
*/
public static <T> int indexOf(final T[] ts, final T t, int start) {
for (int i = start; i < ts.length; ++i)
if (ObjectUtils.equals(ts[i], t))
return i;
return -1;
}
/**
* Find the index of of an object is in given array, starting from 0;
* #param ts Array to be searched in.
* #param t Object to be searched.
* #return indexOf(ts, t, 0)
*/
public static <T> int indexOf(final T[] ts, final T t) {
return indexOf(ts, t, 0);
}
/**
* Detect if the given object is in the given array.
* #param ts Array to be searched in.
* #param t Object to be searched.
* #return If indexOf(ts, t) is greater than -1.
*/
public static <T> boolean in(final T[] ts, final T t) {
return indexOf(ts, t) > -1;
}
}
As you can see in the code above, that there are other utility methods ObjectUtils.equals() and ArrayUtils.indexOf(), that were used at other places as well.
For arrays of limited length use the following (as given by camickr). This is slow for repeated checks, especially for longer arrays (linear search).
Arrays.asList(...).contains(...)
For fast performance if you repeatedly check against a larger set of elements
An array is the wrong structure. Use a TreeSet and add each element to it. It sorts elements and has a fast exist() method (binary search).
If the elements implement Comparable & you want the TreeSet sorted accordingly:
ElementClass.compareTo() method must be compatable with ElementClass.equals(): see Triads not showing up to fight? (Java Set missing an item)
TreeSet myElements = new TreeSet();
// Do this for each element (implementing *Comparable*)
myElements.add(nextElement);
// *Alternatively*, if an array is forceably provided from other code:
myElements.addAll(Arrays.asList(myArray));
Otherwise, use your own Comparator:
class MyComparator implements Comparator<ElementClass> {
int compareTo(ElementClass element1; ElementClass element2) {
// Your comparison of elements
// Should be consistent with object equality
}
boolean equals(Object otherComparator) {
// Your equality of comparators
}
}
// construct TreeSet with the comparator
TreeSet myElements = new TreeSet(new MyComparator());
// Do this for each element (implementing *Comparable*)
myElements.add(nextElement);
The payoff: check existence of some element:
// Fast binary search through sorted elements (performance ~ log(size)):
boolean containsElement = myElements.exists(someElement);
If you don't want it to be case sensitive
Arrays.stream(VALUES).anyMatch(s::equalsIgnoreCase);
Try this:
ArrayList<Integer> arrlist = new ArrayList<Integer>(8);
// use add() method to add elements in the list
arrlist.add(20);
arrlist.add(25);
arrlist.add(10);
arrlist.add(15);
boolean retval = arrlist.contains(10);
if (retval == true) {
System.out.println("10 is contained in the list");
}
else {
System.out.println("10 is not contained in the list");
}
Check this
String[] VALUES = new String[]{"AB", "BC", "CD", "AE"};
String s;
for (int i = 0; i < VALUES.length; i++) {
if (VALUES[i].equals(s)) {
// do your stuff
} else {
//do your stuff
}
}
Arrays.asList() -> then calling the contains() method will always work, but a search algorithm is much better since you don't need to create a lightweight list wrapper around the array, which is what Arrays.asList() does.
public boolean findString(String[] strings, String desired){
for (String str : strings){
if (desired.equals(str)) {
return true;
}
}
return false; //if we get here… there is no desired String, return false.
}
Use below -
String[] values = {"AB","BC","CD","AE"};
String s = "A";
boolean contains = Arrays.stream(values).anyMatch(v -> v.contains(s));
Use Array.BinarySearch(array,obj) for finding the given object in array or not.
Example:
if (Array.BinarySearch(str, i) > -1)` → true --exists
false --not exists
Try using Java 8 predicate test method
Here is a full example of it.
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Test {
public static final List<String> VALUES =
Arrays.asList("AA", "AB", "BC", "CD", "AE");
public static void main(String args[]) {
Predicate<String> containsLetterA = VALUES -> VALUES.contains("AB");
for (String i : VALUES) {
System.out.println(containsLetterA.test(i));
}
}
}
http://mytechnologythought.blogspot.com/2019/10/java-8-predicate-test-method-example.html
https://github.com/VipulGulhane1/java8/blob/master/Test.java
Create a boolean initially set to false. Run a loop to check every value in the array and compare to the value you are checking against. If you ever get a match, set boolean to true and stop the looping. Then assert that the boolean is true.
As I'm dealing with low level Java using primitive types byte and byte[], the best so far I got is from bytes-java https://github.com/patrickfav/bytes-java seems a fine piece of work
You can check it by two methods
A) By converting the array into string and then check the required string by .contains method
String a = Arrays.toString(VALUES);
System.out.println(a.contains("AB"));
System.out.println(a.contains("BC"));
System.out.println(a.contains("CD"));
System.out.println(a.contains("AE"));
B) This is a more efficent method
Scanner s = new Scanner(System.in);
String u = s.next();
boolean d = true;
for (int i = 0; i < VAL.length; i++) {
if (VAL[i].equals(u) == d)
System.out.println(VAL[i] + " " + u + VAL[i].equals(u));
}

Representing multisets as LinkedLists

A multiset is similar to a set except that the duplications count.
We want to represent multisets as linked lists. The first representation
that comes to mind uses a LinkedList<T> where the same item can occur at
several indices.
For example:the multiset
{ "Ali Baba" , "Papa Bill", "Marcus", "Ali Baba", "Marcus", "Ali Baba" }
can be represented as a linked list
of strings with "Ali Baba" at index 0, "Papa Bill" at index 1,
"Marcus" at index 2, "Ali Baba" at index 3, and so on, for a total of
6 strings.
The professor wants a representation of the multiset as pair <item,integer> where the integer, called the multiplication of item, tells us how many times item occurs in the multiset. This way the above multiset is represented as the linked list with Pair("Ali Baba" ,3) at index 0, Pair("Papa Bill", 1) at index 1, and Pair("Marcus",2) at index 2.
The method is (he wrote good luck, how nice of him >:[ )
public static <T> LinkedList<Pair<T,Integer>> convert(LinkedList<T> in){
//good luck
}
the method transforms the first representation into the Pair representation.
If in is null, convert returns null. Also feel free to modify the input list.
He gave us the Pair class-
public class Pair<T,S>
{
// the fields
private T first;
private S second;
// the constructor
public Pair(T f, S s)
{
first = f;
second = s;
}
// the get methods
public T getFirst()
{
return first;
}
public S getSecond()
{
return second;
}
// the set methods
// set first to v
public void setFirst(T v)
{
first = v;
}
// set second to v
public void setSecond(S v)
{
second = v;
}
}
I am new to programming and I've been doing well, however I have no idea how to even start this program. Never done something like this before.
If you are allowed to use a temporary LinkedList you could do something like that:
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
LinkedList<String> test = new LinkedList<String>();
test.add("Ali Baba");
test.add("Papa Bill");
test.add("Marcus");
test.add("Ali Baba");
test.add("Marcus");
test.add("Ali Baba");
LinkedList<Pair<String, Integer>> result = convert(test);
for(Pair<String, Integer> res : result) {
System.out.println(res.getFirst() + " :" + res.getSecond());
}
}
public static <T> LinkedList<Pair<T, Integer>> convert(LinkedList<T> in) {
LinkedList<Pair<T, Integer>> returnList = new LinkedList<>();
LinkedList<T> tmp = new LinkedList<T>();
// iterate over your list to count the items
for(T item : in) {
// if you already counted the current item, skip it
if(tmp.contains(item)) {
continue;
}
// counter for the current item
int counter = 0;
//iterate again over your list to actually count the item
for(T item2 : in) {
if(item.equals(item2)) {
counter ++;
}
}
// create your pair for your result list and add it
returnList.add(new Pair<T, Integer>(item, counter));
// mark your item as already counted
tmp.add(item);
}
return returnList;
}
}
With that i get the desired output of
Ali Baba :3
Papa Bill :1
Marcus :2
Your requirements put:
your input : LinkedList
your output : LinkedList>
1 - write a loop to read your input
2 - process / store it in a convenient way: user Map . In fact, use linkedhashmap which keeps the order
2bis - if you can't use a Map, do the same thing directly with two arrays: an array of T, and an array of integer. You must manager insertion, search, and keep count.
3 - iterate over your arrays, and create your output
It is easier to begin with 2, and if it works, replace with 2bis

classify the values inside array list inside list in java

I am trying to develop a method which receives a List of ArrayList and classify the array list inside it based on the object value. Then, return array list that contains the objects have 1 in their FirstChoice.
the data structure in my code is that
the List has n number of ArrayList, the ArrayList has 24 objects. each object has 3 elements and FirstChoice is one of these elements.
The problem of my code is the output not as i expect , it seems to be just stick with one value and repeat it for the whole list. could you please help me to fix that
ArrayList<HH> TestMethods(List<ArrayList<HH>> s) {
ArrayList<HH> scenario = new ArrayList<HH>();
for (ArrayList<HH> d : s) {
for (int i = 0; i < d.size(); i++) {
if (s.get(i).get(i).FirstChoice == 1) {
scenario.add(s.get(i).get(i));
}
}
}
return scenario;
}
The problem in your code is that when you are looping over the list s, you are actually never using the current element d.
Some other comments on your code:
Prefer returning a List instead of an ArrayList.
Name your methods and variables according to Java naming conventions (testMethods instead of TestMethods, firstChoice instead of FirstChoice)
Be consistent in the way you write loops: use foreach or an index but keep to the same style.
List<HH> testMethods(List<ArrayList<HH>> s) {
List<HH> scenario = new ArrayList<HH>();
for (ArrayList<HH> d : s) {
for (HH hh : d) {
if (hh.firstChoice == 1) {
scenario.add(hh);
}
}
}
return scenario;
}
Your mistakes are on these lines if (s.get(i).get(i).FirstChoice == 1) { and scenario.add(s.get(i).get(i)); as you aren't actually user inner list d.
You're referencing the i'th element of the i'th list of s, when I think you want the i'th element of d where d is a list from s.
ArrayList<HH> TestMethods(List<ArrayList<HH>> s) {
ArrayList<HH> scenario = new ArrayList<HH>();
for (ArrayList<HH> d : s) {
for (int i = 0; i < d.size(); i++) {
int item = d.get(i).FirstChoice;
if (item == 1) {
scenario.add(item);
}
}
}
return scenario;
}

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;
}

Categories

Resources