简体   繁体   中英

ArrayList with Map<K,V> values

I have n number of users with their name and time value eg

String userName = "user1"
String time = "09:30"

In an ArrayList ArrayList<Map<String,String>> userData = new ArrayList<>( ); I would like to have something like this

在此处输入图片说明

But i'm confused with the K,V values. Should i first convert the userName and time in Map values separately? like

Map<String, String> uName = new HashMap<String, String>();
Map<String, String> uTime = new HashMap<String, String>();

uName.put("userName",userName);
uTime.put("time",time);

But then, how to add the two values in the same index of the Array?

Or how which steps should i do first?

Could you please, write down an example or references that could help me as well.

Thank you!

If I understand your question right, you may want to create a class:

public class MyClass {
    private String userName;
    private LocalTime time;
    public MyClass(String userName, LocalTime time) { 
        this.userName = userName;
        this.time = time;
    }

    public String getUserName() { return userName; }
    public LocalTime getUserName() { return time; }
}

The you can simply have an ArrayList<MyClass> . You may want the time variable to be of type String , whatever works best for you. I would not recommend storing timestamps as strings though.

I don't think you need a ArrayList of Maps here, there are two more suitable alternatives in my mind:

  1. Create a class User that will have two string variables - name and time, and have an ArrayList of User
  2. Map that points name->time

either will do, having ArrayList of Maps seems redundant

Just use one map only for each index. For instance:

List<Map<String, String>> userData = new ArrayList<Map<String, String>>();
Map<String, String> user1 = new HashMap<String, String>();
user1.put("name", "John");
user1.put("time", "9:03");
userData.add(user1);

While this works, then if you need to look for any user you'll have to go through the list and find the user you're looking for by accessing the map. So you could have a Map of Maps: Map<String, Map<String, String>> this way:

Map<String, Map<String, String>> userData = new HashMap<String, Map<String, String>>();
Map<String, String> user1 = new HashMap<String, String>();
user1.put("time", "9:03");
userData.put("John", user1);

this way if you're looking for John's data you can just simply do userData.get("John")

An even better solution would be to have a User class with defined properties. For instance:

public class User {
    private String name;
    private String time;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getTime() { return time; }
    public void setTime(String time) { this.time = time; }
}

Map<String, User> userData = new HashMap<String, User>();
User user1 = new User();
user1.setName("John");
user1.setTime("9:03");
userData.put(user1.getName(), user1);

Based on your question "Is it possible to keep the map sorted everytime a user is inserted?" the answer is NO. Maps are unsorted. You seem to need a SortedList that inserts items ordered. Here's a simple Implementation:

    public class SortedList<T> implements List<T> {
  private List<T> delegate;
  private Comparator<T> order;

  public SortedList(List<T> delegate, Comparator<T> order) {
    this.delegate = delegate;
    this.order = order;
  }

  @Override
  public int size() {
    return delegate.size();
  }

  @Override
  public boolean isEmpty() {
    return delegate.isEmpty();
  }

  @Override
  public boolean contains(Object o) {
    return delegate.contains(o);
  }

  @Override
  public Iterator<T> iterator() {
    return delegate.iterator();
  }

  @Override
  public Object[] toArray() {
    return delegate.toArray();
  }

  @Override
  public <T1> T1[] toArray(T1[] a) {
    return delegate.toArray(a);
  }

  @Override
  public boolean add(T t) {
    int i=0;
    for(; i < delegate.size(); i++) {
      if(order.compare(t, delegate.get(i)) < 0) {
        break;
      }
    }
    delegate.add(i, t);
    return true;
  }

  @Override
  public boolean remove(Object o) {
    return delegate.remove(o);
  }

  @Override
  public boolean containsAll(Collection<?> c) {
    return delegate.containsAll(c);
  }

  @Override
  public boolean addAll(Collection<? extends T> c) {
    if (c!= null && !c.isEmpty()) {
      return c.stream().map(this::add).reduce(Boolean.FALSE, (l, r) -> l || r);
    }
    return false;
  }

  @Override
  public boolean addAll(int index, Collection<? extends T> c) {
    throw new IllegalStateException("Can only add in order");
  }

  @Override
  public boolean removeAll(Collection<?> c) {
    return delegate.removeAll(c);
  }

  @Override
  public boolean retainAll(Collection<?> c) {
    return delegate.retainAll(c);
  }

  @Override
  public void clear() {
    delegate.clear();
  }

  @Override
  public T get(int index) {
    return delegate.get(index);
  }

  @Override
  public T set(int index, T element) {
    throw new IllegalStateException("Can only add in order");
  }

  @Override
  public void add(int index, T element) {
    throw new IllegalStateException("Can only add in order");
  }

  @Override
  public T remove(int index) {
    return delegate.remove(index);
  }

  @Override
  public int indexOf(Object o) {
    return delegate.indexOf(o);
  }

  @Override
  public int lastIndexOf(Object o) {
    return delegate.lastIndexOf(o);
  }

  @Override
  public ListIterator<T> listIterator() {
    return delegate.listIterator();
  }

  @Override
  public ListIterator<T> listIterator(int index) {
    return delegate.listIterator(index);
  }

  @Override
  public List<T> subList(int fromIndex, int toIndex) {
    return new SortedList<>(delegate.subList(fromIndex, toIndex), order);
  }

  @Override
  public String toString() {
    return delegate.toString();
  }
}

Which you'll instantiate for instance for a sorted integers list, like this:

SortedList<Integer> nums = 
new SortedList<Integer>(new ArrayList<Integer>(), Comparator.naturalOrder());

Alternatively, you could define your own data structure, say User . Then it goes something like this:

public class User {
    private String name;
    private String time;

   // getters and setters
}

Main advantages to using a data structure as opposed to Map<String, String> include:

  1. Ease of use (no longer need Map , simply a list of User type elements),
  2. Flexibility (perhaps at a later stage you decide to add a location info, this will require modification to the way Map works but it is as simple as adding a field "location" to the data structure).
  3. Clarity of API and code intention. Map<String, String> doesn't say much about what it holds or what it is used for. Conversely, List<User> can be immediately identified as a list of users.
  4. Being a pure data structure, or a Java Bean, it can be easily picked up by IDEs and other frameworks. For instance, serialization of such a class to json becomes a trivial task.

" User " may not be the right name for the type, but the concept applies nonetheless.

You could load a list with Map.Entry:

 final List<Map.Entry<String,String>> listOfEntries =
        new ArrayList<>();
listOfEntries.add(new AbstractMap.SimpleEntry<>("Name", "01:01"));
listOfEntries.add(new AbstractMap.SimpleEntry<>("Name2", "05:10"));

Alternatively, you could load this list with Maps.immutableEntry("firstValue", "secondValue") if you have a Guava dependency.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM