I ran into a bind whereby I had to sort the data read from the phones PIM. In doing this I lost the other to which each contact field was referenced to the telephone number because I made use of 2 separate vectors as illustrated below
Before sorting
Nna - +445535533
Ex - +373773737
Ab - +234575757
After sorting.(Which shouldn't be)
Ab - +445535533
Ex - +373773737
Nna - +234575757
This gives an undesired behavior since the sort removes the index to index pointer of the vectors and a selected name (in a Multiple list Box) will get a wrong number.
Alternatively,
I used a hashtable, with the intention of using the names as keys and numbers as the values.
But this pairing means duplicate names being used as keys will not be allowed. Thus I made it a i.e the phone number as keys instead.
I don't want to sound like a cry baby so I stop here for a while and so you the code with a hope u guys would understand it
MY QUESTION
1. Is there a better way/algorithm to implement this?
2. How do I implement the getSelectedItems() in such a ways that it grabs the numbers of the selected indexes of a MULTIPLE CHOICE LIST from a hashTable
import java.util.Enumeration;
import java.util.Vector;
import java.util.Hashtable;
import javax.microedition.lcdui.List;
import javax.microedition.pim.Contact;
import javax.microedition.pim.ContactList;
import javax.microedition.pim.PIM;
import javax.microedition.pim.PIMException;
/**
*
* #author nnanna
*/
public class LoadContacts implements Operation {
private boolean available;
private Vector telNames = new Vector();
Vector telNumbers = new Vector();
Hashtable Listcontact = new Hashtable();
private String[] names;
public Vector getTelNames() {
return telNames;
}
public Hashtable getListcontact() {
return Listcontact;
}
public void execute() {
try {
// go through all the lists
String[] allContactLists = PIM.getInstance().listPIMLists(PIM.CONTACT_LIST);
if (allContactLists.length != 0) {
for (int i = 0; i < allContactLists.length; i++) {
System.out.println(allContactLists[i]);
System.out.println(allContactLists.length);
loadNames(allContactLists[i]);
System.out.println("Execute()");
}
} else {
available = false;
}
} catch (PIMException e) {
available = false;
} catch (SecurityException e) {
available = false;
}
}
private void loadNames(String name) throws PIMException, SecurityException {
ContactList contactList = null;
try {
contactList = (ContactList) PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_ONLY, name);
// First check that the fields we are interested in are supported(MODULARIZE)
if (contactList.isSupportedField(Contact.FORMATTED_NAME) && contactList.isSupportedField(Contact.TEL)) {
Enumeration items = contactList.items();
Hashtable temp = new Hashtable();
while (items.hasMoreElements()) {
Contact contact = (Contact) items.nextElement();
int telCount = contact.countValues(Contact.TEL);
int nameCount = contact.countValues(Contact.FORMATTED_NAME);
if (telCount > 0 && nameCount > 0) {
String contactName = contact.getString(Contact.FORMATTED_NAME, 0);
// go through all the phone availableContacts
for (int i = 0; i < telCount; i++) {
System.out.println("Read Telno");
int telAttributes = contact.getAttributes(Contact.TEL, i);
String telNumber = contact.getString(Contact.TEL, i);
Listcontact.put(telNumber, contactName);
temp.put(contactName, telNumber);
}
names = getSortedList();
// Listcontact = temp;
System.out.println(temp + "-------");
System.out.println(Listcontact + "*******");
shortenName(contactName, 20);
}
available = true;
}
} else {
available = false;
}
} finally {
// always close it
if (contactList != null) {
contactList.close();
}
}
}
private void shortenName(String name, int length) {
if (name.length() > length) {
name = name.substring(0, 17) + "...";
}
}
public Vector getSelectedItems(List lbx) {
boolean[] arrSel = new boolean[lbx.size()];
Vector selectedNumbers = new Vector();
int selected = lbx.getSelectedFlags(arrSel);
String selectedString;
String result = "";
for (int i = 0; i < arrSel.length; i++) {
if (arrSel[i]) {
selectedString = lbx.getString(lbx.getSelectedFlags(arrSel));
result = result + " " + i;
System.out.println(Listcontact.get(selectedString));
// System.out.println(telNumbers.elementAt(i));
}
}
return selectedNumbers;
}
private String[] sortResults(String data[]) {
RecordSorter sorter = new RecordSorter();
boolean changed = true;
while (changed) {
changed = false;
for (int j = 0; j < (data.length - 1); j++) {
String a = data[j], b = data[j + 1];
if (a != null && b != null) {
int order = sorter.compare(a.getBytes(), b.getBytes());
if (order == RecordSorter.FOLLOWS) {
changed = true;
data[j] = b;
data[j + 1] = a;
}
}
}
}
return data;
}
public String[] getNames() {
return names;
}
Vector elements = new Vector();
private String[] getValueArray(Hashtable value) {
System.out.println(Listcontact + " c");
Enumeration e = value.elements();
while (e.hasMoreElements()) {
elements.addElement(e.nextElement());
}
String[] elementsArray = new String[elements.size()];
elements.copyInto(elementsArray);
elements.removeAllElements();
System.out.println(elementsArray + " k");
return elementsArray;
}
public void getDuplicates(Vector realValue) {
Vector duplicate = new Vector();
Enumeration e = realValue.elements();
for (int i = 0; e.hasMoreElements(); i++) {
if (duplicate.isEmpty() || !duplicate.elementAt(i).equals(e.nextElement())) {
break;
} else {
duplicate.addElement(e.nextElement());
}
}
}
public String[] getSortedList() {
return sortResults(getValueArray(Listcontact));
}
}
Let me reiterate you requirement: You want a method that will sort the contacts read from native phonebook, then alphabetically sort them on name.
Following is the approach,
Replace the vectors and hash-tables in your code with a single vector, say contactListVector, containing elements of type ContactItem, don't worry this class is explained below. Fundamentally the contact's name and number(s) are linked together in a ContactItem, hence you do not have to worry about there mappings which reduces the usage of redundant data structures.
class ContactItem {
private String name;
private String tnumber; //this can also be a data structure
//for storing multiple numbers
ContactItem( String name, String tnumber) {
this.name = name;
this.tnumber = tnumber;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTnumber() {
return tnumber;
}
public void setTnumber(String tnumber) {
this.tnumber = tnumber;
}
}
You can reuse the sorting algorithm on contactListVector by comparing the member variable ContactItem.name of the vector element. Also you can deploy different sorts on member variables numbers and/or names. Also there are lots of libraries for JavaME available that have better sorting algorithm's implemented if need be use them.
I would recommend you to perform the sorting once on the contactListVector elements at the end of your method loadNames(...) maybe in the finally block triggered by some boolean variable. The current sorting call in each iteration on items enumeration is expensive and time consuming.
Also you can serialize / deserialize the ContactItem thus persist your contact list.
Let me know if you need detailed explanation.
What about inserting the contact name and numbers inside a recordStore , so you can later make a sort by creating a class which implements RecordComparator.
This statement in your code makes no sense:
selectedString = lbx.getString(lbx.getSelectedFlags(arrSel))
Per lcdui List API documentation above will return the string located at the index equal to the number of selected elements why would you need that?
If you need to output selected text for debugging purposes, use lbx.getString(i) instead.
To implement the getSelectedItems() in such a ways that it grabs the numbers of the selected indexes of a MULTIPLE CHOICE LIST do about as follows:
public Vector getSelectedItems(List lbx) {
boolean[] arrSel = new boolean[lbx.size()];
Vector selectedNumbers = new Vector();
int selected = lbx.getSelectedFlags(arrSel);
System.out.println("selected: [" + selected + "] elements in list");
String selectedString;
String result = "";
for (int i = 0; i < arrSel.length; i++) {
if (arrSel[i]) {
// here, i is the selected index
selectedNumbers.addElement(new Integer(i)); // add i to result
String selectedString = lbx.getString(i);
System.out.println("selected [" + selectedString
+ "] text at index: [" + i + "]");
}
}
return selectedNumbers;
}
As for sorting needs, just drop the HashTable and use Vector of properly designed objects instead as suggested in another answer - with your own sorting algorithm or one from some 3rd party J2ME library.
I would suggest you to have Contact class with name and Vector of numbers. And instead of sorting names array sort the array of contacts.
Related
For my project I need to add a Creature into an array of creatures thats created in a room
public class Room
{
String name;
String description;
String state;
Creature [] creatures = new Creature[10];
public Room(String roomName)
{
name = roomName;
}
public String toString()
{
String retValue = "";
for (int i = 0; i < creatures.length; i++) {
retValue = retValue + creatures[i].toString();
}
return retValue;
}
public void addCreature(String creatureName)
{
for (int i = 0; i < creatures.length; i++)
{
if(creatures[i] == null)
{
creatures[i] = new Creature(creatureName);
}
}
}
}
when I do this, it overwrites the entire array, what can I do to add a single creature to the array?
Use break statement.
if(creatures[i] == null)
{
creatures[i] = new Creature(creatureName);
break;
}
Arrays have only a fixed size. When you write new Creatures[10], it means that your creatures array has at maximum 10 elements inside of it.
You can add items in two different ways:
You can copy the array and make it bigger, and then add the item
You can use ArrayList, which is a class which automatically does #1 for you
I would recommend ArrayList:
ArrayList:
List<Creature> creatures = new ArrayList<>();
public void addCreature(String creatureName) {
creatures.add(new Creature(creatureName));
}
Seems you miss one condition in if clause. I guess it should be
if(current == null || current.getCreatureName() == null) {
creatures[i] = new Creature(creatureName);
}
I have an arraylist that looks like this:
public static ArrayList<ArrayList<String[]>> x = new ArrayList<>();
I store groups of 2 persons in a pair. For example:
[Person1, Person2]
[Person3, Person4]
The algorithm I use right now still makes duplicates, I've tried out hashmaps and iterating through them with for loop but they just give me back the original list.
This is the code:
package com.company;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
public class createGroups
{
public static ArrayList<ArrayList<String[]>> x = new ArrayList<>();
public static void main(String[] args){
//Define names
String[] names = {"Person1", "Person2", "Person3", "Person4"};
try
{
//Create combinations. In a try catch because of the saveFile method.
combination(names, 0, 2);
//Print all the pairs in the Arraylist x
printPairs();
} catch (IOException e)
{
e.printStackTrace();
}
}
static void combination(String[] data, int offset, int group_size) throws IOException
{
if(offset >= data.length)
{
//Create new Arraylist called foo
ArrayList<String[]> foo = new ArrayList<>();
//Create a pair of 2 (data.length = 4 / group_size = 2)
for(int i = 0; i < data.length / group_size; i++)
{
//Add the pair to foo.
foo.add(Arrays.copyOfRange(data, 2 * i, 2 * (i + 1)));
}
//Add foo to x
x.add(foo);
//saveFile(foo);
}
for(int i = offset; i < data.length; i++){
for(int j = i + 1; j < data.length; j++){
swap(data, offset, i);
swap(data, offset + 1, j);
combination(data, offset + group_size, group_size);
swap(data, offset + 1, j);
swap(data, offset, i);
}
}
}
public static void printPairs(){
//Print all pairs
for(ArrayList<String[]> q : x){
for(String[] s : q){
System.out.println(Arrays.toString(s));
}
System.out.println("\n");
}
}
private static void swap(String[] data, int a, int b){
//swap the data around.
String t = data[a];
data[a] = data[b];
data[b] = t;
}
}
The output right now is this:
Output
Every group of 4 names is a 'list' of pairs (Not really a list but that's what I call it)
And this is the desired output:
Desired output
But then you can see that the first and the last list of pairs are basically the same how do I change that in my combination method
The question:
How can I change my combination method so that it doesn't create duplicate groups.
And how can I make the list smaller (The desired output) when printing the created lists.
If I wasn't clear enough or if I didn't explain what I want very well, let me know. I'll try to make it clearer.
Create an object similar to this. It takes 4 strings (2 pairs). Puts the strings into array and sorts this array. That means any combination of strings you put in will be converted into one sorted combination, but the object internaly remembers which person is person1, person2, ...
private class TwoPairs {
private final String person1;
private final String person2;
private final String person3;
private final String person4;
private final String[] persons;
TwoPairs(String person1, String person2, String person3, String person4) {
this.person1 = person1;
this.person2 = person2;
this.person3 = person3;
this.person4 = person4;
persons = new String[4];
persons[0] = person1;
persons[1] = person2;
persons[2] = person3;
persons[3] = person4;
// if we sort array of persons it will convert
// any input combination into single (sorted) combination
Arrays.sort(persons); // sort on 4 objects should be fast
// hashCode and equals will be comparing this sorted array
// and ignore the actual order of inputs
}
// compute hashcode from sorted array
#Override
public int hashCode() {
return Arrays.hashCode(persons);
}
// objects with equal persons arrays are considered equal
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
TwoPairs other = (TwoPairs) obj;
if (!Arrays.equals(persons, other.persons)) return false;
return true;
}
// add methods which you might need
// getters for individual persons
// String getPerson1() { return person1; }
// or perhaps pairs of persons
// String[] getPair1() { return new String[] {person1, person2}; }
// add sensible toString method if you need it
}
Your ArrayList x will change like this
ArrayList<TwoPairs> x = new ArrayList<TwoPairs>();
before adding new TwoPairs object into x check if this list already contains this object.
if (!x.contains(twoPairsObject)) {
x.add(twoPairsObject);
}
I have this class with several attributes something like this:
public class FileIn {
public String id;
public void setID(String id_) {
id = id_;
}
public String getID() {
return id;
}
...
}
There are 20 attributes.
Then i put this data in one ArrayList:
public ArrayList<FileIn> dfor_A = new ArrayList<FileIn>();
Well, later i need to get the index of one element, but i know the id
dfor_A.get(-unknow index-).getID();
How can i search and get the index?
Solution 1 :
I think you have to loop
/*function perform operation dfor_A.indexOf(item.id);*/
public int getIndexOf(String id,List dfor_A)
{
for (int i = 0; i < dfor_A.size(); i++) {
FileIn fi = dfor_A.get (i);
if (fi.getID().equals (id)) {
return i; // this is the index
}
}
return -1;
}
Solution 2 :
if you think about good performance of it. I suggest you to use advanced features
Step 1 :Implement Comparator
public class FileInCustomComparator implements Comparator<FileIn> {
#Override
public int compare(FileIn fileIn1, FileIn fileIn2) {
return fileIn1.getId()-fileIn2.getId();//id consider as int here
}
}
Step 2 :Sort the list
Collections.sort( for_A /*list here*/, new FileInCustomComparator());
Step 3 :Search the Sorted list using optimized inbuilt algorithm
public void search(String key,List list) {
System.out.println("\nSearching for " + key);
int result = Collections.binarySearch(list, key);
if (result >= 0)
System.out.print(" Found at index " + result);
else
System.out.print(" Not found [" + result + "]");
}
Use a Map e.g. HashMap
Map <String, FileIn> map = new HashMap <> ();
map.put (fileIn.getID (), fileIn);
later
FileIn fileIn = map.get (fileIn.getID ());
If you really want to keep an ArrayList, then you will need to loop
for (int i = 0; i < dfor_A.length; i++) {
FileIn fi = dfor_A.get (i);
if (fi.getID().equals (id)) {
return i; // this is the index
}
}
Implementing a Linked List, store up to 10 names, ordered in first in First Out. Then implement two methods, one of which to sort it alphabetically by last names. This is where I am having some trouble. Here is what I tried:
Recursion. The method calls two nodes, compare them, swap if needed and then calls itself. Doesn't work with odd number of names and tends to be full bugs.
Collection but I don't know enough about it to use it effectively.
Sorting algorithms (ex. bubble sort): I can go though the list but have a hard time getting the nodes to swap.
My question is: What is the easiest way to do this?
public class List
{
public class Link
{
public String firstName;
public String middleName;
public String lastName;
public Link next = null;
Link(String f, String m, String l)
{
firstName = f;
middleName = m;
lastName = l;
}
}
private Link first_;
private Link last_;
List()
{
first_ = null;
last_ = null;
}
public boolean isEmpty()
{
return first_ == null;
}
public void insertFront(String f, String m, String l)
{
Link name = new Link(f, m, l);
if (first_ == null)
{
first_ = name;
last_ = name;
}
else
{
last_.next = name;
last_ = last_.next;
}
}
public String removeFront()
{
String f = first_.firstName;
String m = first_.middleName;
String l = first_.lastName;
first_ = first_.next;
return f + " " + m + " " + l;
}
public String findMiddle(String f, String l)
{
Link current = first_;
while (current != null && current.firstName.compareTo(f) != 0 && current.lastName.compareTo(l) != 0)
{
current = current.next;
}
if (current == null)
{
return "Not in list";
}
return "That person's middle name is " + current.middleName;
}
}
public class NamesOfFriends
{
public static void main(String[] args)
{
List listOfnames = new List();
Scanner in = new Scanner(System.in);
for(int i = 0; i < 3; i++)
{
if(i == 0)
{
System.out.println("Please enter the first, middle and last name?");
listOfnames.insertFront(in.next(), in.next(),in.next());
}
else
{
System.out.println("Please enter the next first, middle and last name");
listOfnames.insertFront(in.next(), in.next(),in.next());
}
}
System.out.println("To find the middle name, please enter the first and last name of the person.");
System.out.println(listOfnames.findMiddle(in.next(),in.next()));
}
}
Edit
After working on it a bit, I figured out how to go about sorting it. For that purpose, I am trying to implement a remove method that can remove a node anywhere on the list. While it does compile, it doesn't do anything when I run the program.
public Link remove(String lastName)
{
Link current_ = first_;
Link prior_ = null;
Link temp_ = null;
while (current_ != null && current_.lastName.compareTo(lastName) != 0)
{
prior_ = current_;
current_ = current_.next;
}
if (current_ != null)
{
if (current_ == last_)
{
temp_ = last_;
last_ = prior_;
}
else if (prior_ == null)
{
temp_ = first_;
first_ = first_.next;
}
}
else
{
temp_ = current_;
prior_.next = current_.next;
}
return temp_;
}
2: Collections is the easiest, but it seems to be not allowed in your homework
3: BubbleSort is easy but the worst known sorting algo, however for your homework it probably is ok
1: This is the same as bubble sort, but is prefered to be done without recursion
In BubbleSort you loop through your elements again and again till no swaps are neeeded anymore, then you are ready.
Collection is the easiest way to accomplish this.
Implement Comparable
Override hashcode and equals
Collection.sort()
You already has the linked list implemented, that is good.
Have you considered implementing MergeSort as the sorting algorithm? Being the divide&conquer algorithm, you will always end up with only two elements to form a list with.
The merge part is going to be trickier, but also easy. Basically you just create a new list and start filling it up with elements you get by comparing the first values of the two merging sets.
So for instance if you have two sets to merge:
[A]->[C]->[D]
[B]->[E]->[F]
the mergin process will go:
[A]
[C]->[D]
[B]->[E]->[F]
[A]->[B]
[C]->[D]
[E]->[F]
[A]->[B]->[C]
[D]
[E]->[F]
[A]->[B]->[C]->[D]
[E]->[F]
[A]->[B]->[C]->[D]->[E]
[F]
[A]->[B]->[C]->[D]->[E]->[F]
I have two different arrays an ArrayList of doubles and an Array of Strings
public class tester {
private final static String TIME[]={ "8:00", "9:00", "10:00", "11:00",
"12:00", "13:00", "14:00", "15:00", "16:00", "17:00", "18:00", "19:00" };
public static void main(String[] args){
ArrayList<Double> stat = new ArrayList<>();
stat.add(1.0);
stat.add(2.0);
stat.add(3.0);
stat.add(4.0);
stat.add(5.0);
stat.add(6.0);
stat.add(7.0);
stat.add(8.0);
stat.add(9.0);
stat.add(10.0);
stat.add(11.0);
stat.add(12.0);
int i = 0;
for (String time : TIME) {
System.out.println(time+" "+stat.get(i));
i++;
}
My question is quite simple is this the best way to loop through each array if I want to get the same position of each array to match? so that stat.get(0) ==TIME.get(0)?
Update
First of all thank you all for your quick response i like the idea of creating a class however there is something you need to know.
The thing you saw was a test class that i use to test my data.
i KNOW that the two arrays will ALWAYS be the same size due to the fact that the stat ArrayList normally defined like the following:
stat is a calculated value of data gained from the database the value of stat is based on time and then sent back to the GUI to be put into a graph and a table.
This means that for each of the TIME there is an exisiting value so that stat.get(0) is ALWAYS equal to TIME.get(0) == "8:00".
With this in mind do you still think i should create a class or should i keep the class showed below and then add a HashMap containing the data then iterate over that map to insert the data in my GUI?
public class Statistics {
private ArrayList<CallQueue> queues = new ArrayList<CallQueue>();
private ArrayList<Double> averageData = new ArrayList<Double>();
private Provider p;
public Statistics(){
try {
this.p = new Provider();
} catch (DopeDBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* This recursive method calculates the average of each time table and then adds its to the arrayList in the following order:
* 8.00 = 0
* 9.00 = 1
* 10.00 = 2
* 11.00 = 3
* 12.00 = 4
* 13.00 = 5
* 14.00 = 6
* ect.
* #param time
*/
public void calculateAverage(){
int data = 0;
for (int i = 8; i < 20; i++) {
for (CallQueue cq : queues) {
data += cq.getCallsByTime(i);
}
if (data == 0) {
Main.createErrorMessage("Fejl i dataen! \r\n kontakt venligst ansvarlige i Dope");
}
averageData.add((double) data/11);
}
}
/**
* #author MRCR
* This method recives the object list from the database and sets the currentlist to the list recived.
*/
public void setQueues(Calendar start, Calendar end){
try {
queues = p.getInformation(start, end, queues);
} catch (DopeDBException e) {
// TODO Auto-generated catch block
Main.createErrorMessage("Message");
} catch (DopeResultSetException e) {
// TODO Auto-generated catch block
Main.createErrorMessage("Message");
}
}
/**
* This method returns the calculated DataList list.
* #author MRCR
* #return averageData
*/
public ArrayList<Double>getData(Calendar start, Calendar end){
setQueues(start, end);
calculateAverage();
return averageData;
}
}
import java.util.HashMap;
public class CallQueue {
private String type;
private HashMap<Integer, Integer> data = new HashMap<Integer,Integer>();
public CallQueue(String type){
this.type = type;
}
public String getType(){
return type;
}
public int getCallsByTime(int time){
return data.get(time);
}
public void addCallsByTime(int hourOfDay, int callAmount) {
data.put(hourOfDay, callAmount);
}
}
I would first check that the lengths of the 2 arrays are the same.
Then iterate using a for loop:
final int timeLength = TIME.length;
if (timeLength != stat.size()) {
//something may not be right
}
for (int i = 0; i < timeLength; i++) {
System.out.println(time[i]+" "+stat.get(i));
}
for (int i = 0; i < TIME.length; i++) {
// use i to access TIME[i] and stat.get(i)
}
but you have to ensure that those arrays are of the same length
You would need to consider the length part also. You would only need to iterate upto the maximum length possible that covers both array, and list.
So, you can first find the lower length between them. And then iterate till that length: -
int lower = TIME.length < stat.size()? TIME.length: stat.size();
for (int i = 0; i < lower; i++) {
System.out.println(TIME[i] + " : " + stat.get(i);
}
Now that was the part of iterating over two arrays.
Now I would say, if you have to iterate over two arrays simultaneously, just make a class with the attributes, you have created arrays for.
So, create a class with attributes: - time, and stats. And then create a List<YourClass>. And iterate over the list of the class instances.
if (TIME.length!=stat.size()) {
// handle error
}
int count = stat.size();
for (int i=0; i<count; ++i) {
double d = stat.get(i);
String s = TIME[i];
}
However
As pointed out in a comment, you should define a class that will gather the information of both arrays.
For instance:
public class MyTime {
private double value;
private String label;
}
Or
In that particular case, I suspect you could use time formatting functions to replace your string array.
String.format("%1$d:00", (int) myDouble);