[英]Move up, move down, specify position
我知道这似乎很基本,但是由于某种原因,我只是无法解决解决该问题的算法,所以我将就这个问题与社区联系。
我有一堂课,看起来像这样:
class MapElementModel {
int id;
String name;
int position;
//other fields ommitted for space reasons
//getters and setters
}
现在,我将MapElementModel存储在标准ArrayList中。 用户想在列表中上移元素,在列表中下移元素,或为MapElementModel指定新位置。 该列表基于MapElementModel.position进行排序。
因此,基本上,如果用户将项目14移动到位置3,则需要将该项目插入位置3,位置字段需要更改为3,并且随后的所有位置都需要相应更改。
同样,用户可以单击“上移”按钮,然后将位置9处的项目移动到位置8。同样,所有其余MapElementModel.position项目都需要相应地更改其位置字段。
最后,用户可以单击“下移”按钮,然后将列表中的项目下移。 同样,必须更新所有MapElementModel.position字段。
有人对此问题有好的解决方案吗? 谢谢您的帮助!
最简单的解决方案是放弃使用ArrayList
来存储它们。 而是考虑使用LinkedList
。 当您要交换对象并通过从邻居到邻居遍历列表时,链表是非常好的数据结构。 删除对象,添加对象或交换两个对象会自动更新所有“索引”,因为您不再具有索引,而只需与根项目保持距离即可。
但是,如果您确实希望使用ArrayList实现,那么是的,您是正确的。 您最有可能想到的问题是,您必须遍历需要更改的项目,并用索引i-1
的项目换出索引i
的项目。 执行此操作时,将创建许多临时对象以处理每次交换。
您的代码看起来很笨拙,而且速度很慢(假设您要进行大量交换),但这是使用ArrayList的代价。 好处是您可以直接通过索引i
访问项目,而不必从根对象开始遍历LinkedList中的i
项目。
您说:“列表是根据MapElementModel.position排序的”,因此我的答案将基于此。 如果根据MapElementModel.id进行排序,则将是另一种算法。
将ArrayList
视为项目的有序集合。 而不是“存储” MapElementModel中的位置,只需让ArrayList
元素的索引为其位置即可。 例如,如果您的ArrayList
具有元素["Red", "Blue", "Green", "Yellow", "Pink", "Purple"]
,则“ Red”的位置为0,而“ Blue”的位置“为1,而“绿色”的位置为2,依此类推...
我假设您不太关心效率-即您没有处理10亿个项目。
现在,要移动项目,我们的算法是简单地将其从列表中删除,然后再次将其插入正确的位置。 假设我们又有了列表:
["Red", "Blue", "Green", "Yellow", "Pink", "Purple"]
让我们考虑一些测试用例:
在第一种情况下,我们将“黄色”移到“红色”的前面。 所以像这样删除“黄色”
String removed = list.remove( 3 );
现在我们要将其插入位置0。看起来我们可以
list.add( 0 , removed );
简单吧? 删除给定索引处的元素,将其插入所需索引处。 让我们看看它是否适用于第二个测试用例。
在情况2中,我们要将“ Yellow”移动到位置5。请注意,列表中有六个元素,而位置5对应于第六个位置(如果数组索引从0开始),因此“ Yellow”将转到列表的末尾,在“紫色”之后。 因此,我们再次删除“黄色”:
String removed = list.remove( 3 );
但是现在看,黄色之后的一切都向下移动了1:
["Red, "Blue", "Green", "Pink", "Purple"]
方便地,“ Purple”的索引是4,如果我们在位置5插入
list.add( 5 , removed );
我们得到
["Red, "Blue", "Green", "Pink", "Purple"]
看看该算法是否可以将黄色放置在位置3(多余的情况)下。
看起来我们的算法的工作原理如下:在给定位置删除,在目标位置插入。 看来我们可以编写这样的算法:
public void moveItem( int idxToMove , int targetIdx ) {
String removed = list.remove( idxToMove );
list.add( targetIdx , removed );
}
如果用户想将项目在位置3上移1个位置,请致电
moveItem( 3 , 3+1 );
如果用户希望将位置3的项目向下移动列表中的1个位置,则您可以调用
moveItem( 3 , 3-1 );
如果用户想将位置0处的项目向下移动列表中的1点,该怎么办?
如果用户要将位置5的项目移动到位置2的项目,请致电
moveItem( 5 , 2 );
现在,您可以为MapElementModel的ArrayList实现此算法。 如果您确实需要MapElementModel对象的position
字段正确,则只需遍历ArrayList并对其进行更新。 元素在ArrayList中的位置是元素的位置。
public void moveItem( int idxToMove , int targetIdx ) {
//move the item as I did with Strings
for ( int i=0 ; i<list.size() ; i++ ) {
list.get( i ).position = i;
}
}
如果需要移动具有指定ID的项目,则可以在ArrayList中找到它,然后移动它:
public void moveItemById( int itemId , int newPosition ) {
int positionOfItem = -1;
for ( int i=0 ; i<list.size() ; i++ ) {
if ( list.get( i ).id == itemId ) {
positionOfItem = i;
break;
}
}
if ( positionOfItem != -1 ) {
moveItem( positionOfItem , newPosition );
}
}
为什么不实现通用的东西? 在这种情况下,我将使用LinkedList,但可以改为扩展ArrayList。
public class MovableList<T> extends LinkedList<T> {
public MovableList() {
super();
}
public MovableList(Collection<T> c) {
super(c);
}
/** Returns removed elements */
public Collection<T> remove(int[] indexes) {
Collection<T> removeList=new ArrayList(indexes.length);
for(int index: indexes){
removeList.add(get(index));
}
removeAll(removeList);
return removeList;
}
/** Returns inserted elements */
public Collection<T> insert(List<T> from, int[] indexes, int position) {
Collection<T> insertList=new ArrayList(indexes.length);
Arrays.sort(indexes);
for(int index: indexes){
insertList.add(from.get(index));
}
addAll(position, insertList);
return insertList;
}
public void moveTo(int[] indexes, int position) {
Arrays.sort(indexes);
addAll(position, remove(indexes));
}
}
public void shift(List<String> currentList, String element, int places) {
int fromPos = -1;
int toPos = 0;
if (places != 0) {
//Creates a new list
List<String> newList = new ArrayList<>();
// get curren position
fromPos = currentList.indexOf(element);
if (fromPos >= 0) {
// If was found, calculates new position
toPos = fromPos - places;
if (toPos >= 0 && toPos < currentList.size()) {
// new position is in range
if (places > 0) {
//move forward
if (toPos == 0) {
// move at the head
newList.offer(element);
newList.addAll(currentList.subList(0, fromPos));
newList.addAll(currentList.subList(fromPos + 1, currentList.size()));
} else {
// some places forward
newList.addAll(currentList.subList(0, toPos));
newList.offer(element);
newList.addAll(currentList.subList(toPos, fromPos));
newList.addAll(currentList.subList(fromPos + 1, currentList.size()));
}
} else {
//move backward
if (toPos == (currentList.size() - 1)) {
// move at the end of the list
newList.addAll(currentList.subList(0, fromPos));
newList.addAll(currentList.subList(fromPos + 1, currentList.size()));
newList.offer(element);
} else {
// move some places backward
newList.addAll(currentList.subList(0, fromPos));
newList.addAll(currentList.subList(fromPos + 1, toPos + 1));
newList.offer(element);
newList.addAll(currentList.subList(toPos + 1, currentList.size()));
}
}
// replace old list
currentList = newList;
newList = null;
}
}
}
}
真正的问题是您需要保持同步的冗余信息。 “位置”存储在两个位置:
List
,依靠哪个list元素包含对象 MapElementModel
本身中,在position
字段中 您应该考虑摆脱其中一种,以避免保持它们同步。 MapElementModel
是否真的需要知道它在包含它的列表中的位置?
如果确实必须同时保留两者,则需要:
position
字段 position
也已更改的所有元素的position
字段 所以:
// remove the element from the list
oldPosition = element.getPosition();
list.remove(oldPosition);
// insert the element in its new position
list.add(newPosition, element);
// the elements with new positions are those with positions
// greater than or equal to the new position or the old position,
// whichever is lower
for(int i = Math.min(newPosition,oldPosition); i<list.size(); i++) {
list.get(i).setPosition(i);
}
这并不是特别有效,但这就是您选择的数据结构的局限性。
您想要的是ArrayList
非常昂贵的操作。 它要求将列表开头和C
位置之间的每个元素下移一个。
但是,如果您确实想要这样做:
int index = url.indexOf(itemToMove);
url.remove(index);
url.add(0, itemToMove);
如果这是您的常用操作,并且随机访问的频率相对较低,则可以考虑切换到另一个List
实现,例如LinkedList
。 如果您非常关注元素的顺序,则还应该考虑列表是否完全是正确的数据结构。
另一方面,如果只是移动一行
最多:
int index = items.indexOf(myObject);
Collections.swap(items, index, Math.max (0, index - 1));
Donwn:
int index = items.indexOf(myObject);
Collections.swap(items, index, Math.min (items.size () - 1, index + 1));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.