【问题标题】:Remove an array of ids contained in another array删除另一个数组中包含的 id 数组
【发布时间】:2016-01-27 00:18:37
【问题描述】:

如果我有一个 Track 对象数组:

Track[] tracks;

每个轨道都有许多字段,其中包括一个字符串 trackId:

public class Track{

    private String trackId;


    private String artistId;
}

那我有

String trackIdsToRemove[];

我想删除 trackIdsToRemove[] 中的 ID,它们位于曲目列表内的对象中。

除了迭代之外,还有什么奇特的方法可以做到这一点吗?也许与番石榴?还是 RxJava?

【问题讨论】:

  • 鉴于您提供的信息,不。如果主数组按 trackId 排序,则可以对它们进行二进制搜索。此外,您不能真正从数组中“删除”,最多可以将单元格的内容设置为 null。

标签: java arrays optimization guava rx-java


【解决方案1】:

如果您使用的是 java 8 和 Guava:

Set<String> toRemove = Sets.newHashSet(trackIdsToRemove);
tracks = Arrays.stream(tracks)
    .filter(t -> !toRemove.contains(t.trackId))
    .toArray(Track[]::new);

【讨论】:

    【解决方案2】:

    无论你使用什么技巧/库,后端每次都是一样的,你需要找到要删除的元素,然后继续实际删除它。

    但是你可以做一些小的优化,首先是采用最好的数据结构。如果您要经常添加/删除曲目,也许您应该使用列表而不是数组。
    然后您还可以按顺序插入曲目,以便在需要找到要删除的曲目时进行二进制搜索。二进制搜索需要O(log(n)) 在最坏的情况下找到轨道,而普通搜索需要O(n)

    有用的链接:http://bigocheatsheet.com/#data-structures

    【讨论】:

      【解决方案3】:

      您可以使用 ArrayList:

      ArrayList array = new ArrayList();
      //add elements to array -> array.add(object1);
      ArrayList arrayToRemove = new ArrayList();
      //add elements to array to remove -> array.add(object1);
      for(Object obj : arrayToRemove){
         array.remove(obj);
      }
      

      为此,如果您使用自己的对象,则需要覆盖下一个对象函数equalshashCode,以下是此线程上的示例:

      【讨论】:

      • 值得一提的是,这种方法会创建数据副本:如果 OP 担心性能,可能是因为集合很大,因此复制数据可能不可行。
      • @DiegoMartinoia 我认为他可以更改对象。如果 OP 有一个原始数组,最好自己进行迭代并使用结果创建一个新副本。
      【解决方案4】:

      我不确定您所说的从数组中“删除”是什么意思:您根本不能这样做,您最多可以将单元格内容设置为空或以某种方式将其标记为无效/免费。

      如果你的数组是按id排序的,你可以对想要“移除”的id进行二分查找以获得更好的性能:假设N是集合的大小,M是移除集合的大小,那么正常迭代是O(n*m),而通过二进制搜索你可以得到 O(log(n)*m)

      一般来说,即使您有一个库,它也会在幕后对这些数据结构执行此操作。

      正如其他人指出的那样,如果您需要支持删除,最好使用不同的结构:如果您有 ID,则表明您的项目是唯一的,因此 Set 可能是理想的,否则应该使用 List 或 Map Obj -> Int 实现多集。

      假设您可以更改代码以使用更理想的结构,您可以执行类似 (Java8) 的操作:

      Set<Track> tracks;
      Set<String> idsToRemove;
      //Note: this has O(n*m) performance, though you could try using .parallelstream() instead of .stream()
      Set<Track> remainingOnes = tracks.stream().filter(x -> !idsToRemove.contains(x.id)).collect(Collectors.toSet());
      

      【讨论】:

        【解决方案5】:

        您不能从数组中删除。您可以从列表中删除。将您的数组更改为列表并这样做:

        public void remove(String trackIdsToRemove[], List<Track> tracks) {
            for(String str: trackIdsToRemove) {
                tracks.remove(tracks.indexOf(str));
            }
        }
        

        【讨论】:

        • 如果您真的必须按列表进行操作,那么您可能会将 trackIdsToRemove 作为列表并执行 removeAll。但请注意,trackToRemove 是 ID 的集合,而不是 Track 对象的集合,因此您需要相应地调整代码:因为现在它不会编译 bc 类型不兼容
        • removeAll()的参数是一个列表类型的Collection。事实并非如此。如果我将字符串数组传递给 Track 列表的 removeAll(),它不会删除所有 Track。请在投票前搜索您的答案。
        • 这正是我所说的:如果你有一个曲目的集合,你可以使用 remove 或 removeAll,但是你有一个字符串(id)的集合,所以你不能使用它们:你的indexOf 方法会在这里失败,因为你传递了一个字符串
        猜你喜欢
        • 2014-06-07
        • 2016-03-15
        • 1970-01-01
        • 2013-11-26
        • 2016-12-05
        • 1970-01-01
        • 2011-05-20
        • 2013-05-06
        • 2021-07-27
        相关资源
        最近更新 更多