字符串列表获取一个没有循环的项目

时间:2016-10-15 12:39:56

标签: java arraylist collections

我有一个包含数千个数据的数组列表。

例如:

List<String> custNames = new ArrayList<String>();
custNames.add("John");
custNames.add("Tom");
custNames.add("Bart");
custNames.add("Tim");
custNames.add("Broad");

现在我想获得仅以'T'开头的名字数量。我使用循环机制来解决问题。

List<String> filterNames = new ArrayList<String>();
String nameStarts="T";
for(int i=0;i<custNames.size();i++)
{
    if(custNames.get(i).toLowerCase().startsWith(nameStarts.toLowerCase()))
    {
        filterNames.add(custNames.get(i));
    }
}
System.out.println(filterNames.size());

但是我在这个custNames列表中有非常大的数据集合。 没有使用循环有没有不同的解决方案?

感谢。

8 个答案:

答案 0 :(得分:5)

Java 8为您的问题提供了非常好的解决方案。

试试这个,

long filterNameCount = custNames
        .stream()
        .parallel() 
        .filter((s) -> s.startsWith(nameStarts.toLowerCase()))
        .count();

System.out.println(filterNameCount);

答案 1 :(得分:3)

如果您愿意使用第三方库,可以使用Eclipse Collections一些有趣的选项。

如果您使用上面的ArrayList,则可以使用LazyIterate实用程序,如下所示:

int count = LazyIterate.collect(custNames, String::toLowerCase)
        .countWith(String::startsWith, nameStarts.toLowerCase());
Assert.assertEquals(2, count);

如果您使用ArrayList的Eclipse Collections替换,则可以使用MutableList上直接提供的丰富功能协议:

MutableList<String> custNames =
        Lists.mutable.with("John", "Tom", "Bart", "Tim", "Broad");
String nameStarts= "T";
int count = custNames.asLazy()
        .collect(String::toLowerCase)
        .countWith(String::startsWith, nameStarts.toLowerCase());
System.out.println(count);
Assert.assertEquals(2, count);

Eclipse Collections中的串行API是默认的,这就是我首先调用asLazy()的原因。否则,collect方法会创建另一个MutableList

如果您使用完整的数据集对代码进行基准测试,则以下并行版本的代码可能会更高效:

MutableList<String> custNames =
        Lists.mutable.with("John", "Tom", "Bart", "Tim", "Broad");
String nameStarts= "T";
int processors = Runtime.getRuntime().availableProcessors();
int batchSize = Math.max(1, custNames.size() / processors);
ExecutorService executor = Executors.newFixedThreadPool(processors);
int count = custNames.asParallel(executor, batchSize)
        .collect(String::toLowerCase)
        .countWith(String::startsWith, nameStarts.toLowerCase());
executor.shutdown();
Assert.assertEquals(2, count);

Eclipse集合中的asParallel() API默认是惰性的。 API会强制您传入ExecutorServiceint batchSize。这使您可以完全控制并行性。

您还可以将Eclipse API与Eclipse集合中的所有MutableCollections一起使用,因为它们会扩展java.util.Collection

注意:我是Eclipse Collections的提交者。

答案 2 :(得分:0)

您还可以使用树存储:这种搜索非常有效。如果你被列入一个列表,之前的回答是一种方法。

答案 3 :(得分:0)

如果您有更多或更少的静态列表并经常执行搜索操作,您可以对列表进行排序或使用TreeMap。

此外,您不需要创建新列表并获得其大小。您只需创建一个计数器变量并递增它即可。

答案 4 :(得分:0)

删除所有不以“T”开头的项目:

custNames.removeIf(p->!p.startsWith("T"));

您可以从列表中复制一份,并删除不以“T”开头的项目。

答案 5 :(得分:0)

首先,您可以使用function hello_header_menu() { // display the WordPress Custom Menu if available wp_nav_menu(array( 'menu' => 'primary', 'theme_location' => 'primary', 'depth' => 2, 'container' => 'div', 'container_class' => '', 'menu_class' => 'navbar-nav nav', 'fallback_cb' => 'hello_wp_bootstrap_navwalker::fallback', 'walker' => new hello_wp_bootstrap_navwalker() )); } /* end header menu */ endif; 缩短初始化时间;其次,我将使用一个简单的循环来构建计数表一次,然后使用它来确定后续查询。像,

Arrays.asList(T)

哪个输出

List<String> custNames = new ArrayList<String>(Arrays.asList("John", "Tom", 
        "Bart", "Tim", "Broad"));
int[] counts = new int[26];
for (String name : custNames) {
    char ch = Character.toLowerCase(name.charAt(0));
    counts[ch - 'a']++;
}
for (int i = 0; i < counts.length; i++) {
    if (counts[i] > 0) {
        System.out.printf("There are %d words that start with %c%n", 
                counts[i], (char) ('a' + i));
    }
}

或者,在特定情况下,There are 2 words that start with b There are 1 words that start with j There are 2 words that start with t 是以counts['t' - 'a']开头的字数。

答案 6 :(得分:0)

如果存储项目的顺序无关紧要,您可以将名称存储在HashMap中,其中每个名称的第一个字符是键,并且具有该第一个字符的名称的ArrayList是值。然后,假设HashMap名为customerList,则需要做的就是customerList.get(&#34; T&#34;)。size()。

初始化HashList并添加客户

HashMap<Character, ArrayList<String>> customerList = new HashMap<Character, ArrayList<String>>();
int NUM_ALPHABETS = 26;
int ascii_char = 97;
for(int i = 0; i < NUM_ALPHABETS; i++){
  char c = (char) ascii_char;
  customerList.add(c, new ArrayList<String>());
  ascii_char++;
}

customerList.get("t").add("Tony");
customerList.get("a").add("Alice");
customerList.get("b").add("Ben");

获取以&#34; t&#34;

开头的客户数量
 int num_t = customerList.get("t").size();

答案 7 :(得分:0)

您可以创建自己的排序和查找实现。

请考虑以下事项:

public class ContainingArrayList<E> extends ArrayList<E> {
    private Comparator<E> comparator;

    public ContainingArrayList(Comparator<E> comparator) {
        this.setComparator(comparator);
    }

    @Override
    public boolean add(E e) {
        // If the collection is empty or the new element is bigger than the last one, append it to the end of the collection
        if(size() == 0 || comparator.compare(e, get(size()-1)) >= 0)
            return super.add(e);
        else {
            for (int i = 0; i < size(); i++) {
                int result = comparator.compare(e, get(i));
                // If the new element is bigger than the current element, continue with the next element
                if (result > 0) continue;
                // If the new element is equal to the current element, no need to insert (you might insert of course)
                if (result == 0) return false;
                // Otherwise the new element is smaller than the current element, so insert it between the previous and the current element
                super.add(i, e);
                return true;
            }
            return super.add(e);
        }
    }

    public E get(E containingElement) {
        int start = 0;
        int end = size()-1;
        // If the element is the first one, return the first element
        if(comparator.compare(containingElement, super.get(start)) == 0)
            return super.get(start);
        // If the element is the last one, return the last element
        if(comparator.compare(containingElement, super.get(end)) == 0)
            return super.get(end);

        // Otherwise do a binary search
        while(start != end) {
            // Get the element between start and end positions
            E mid = super.get(start + (end/2));
            // Compare the two elements
            int result = comparator.compare(containingElement, mid);
            // If the middle element compared to the containing element is equal, return the middle element
            if(result == 0) {
                return mid;
            }
            // If the containing element is smaller than the middle, halve the end position
            else if(result < 0) {
                end = start + (end/2);
            }
            // If the containing element is bigger than the middle, set the start position to the middle position
            else if(result > 0) {
                start = start + (end/2);
            }
        }
        return null;
    }


    public Comparator<E> getComparator() {
        return comparator;
    }

    public void setComparator(Comparator<E> comparator) {
        this.comparator = comparator;
    }
}

自定义比较器用于对元素进行排序并查找以特定字符开头的元素。这意味着您可以随时根据需要更改比较器实现,也可以创建更加动态的查找解决方案。

测试:

public class SortFindTest {

    public SortFindTest() {
        ContainingArrayList<String> t = new ContainingArrayList<String>(new MyComparator());
        t.add("John");
        t.add("Tom");
        t.add("Bart");
        t.add("Tim");
        t.add("Broad");

        System.out.println(t.get("T"));
    }

    class MyComparator implements Comparator<String> {
        @Override
        public int compare(String o1, String o2) {
            int o1c = o1.charAt(0);
            int o2c = o2.charAt(0);
            if(o1c == o2c)
                return 0;
            if(o1c > o2c)
                return 1;
            return -1;
        }

    }

    public static void main(String[] args) {
        new SortFindTest();
    }
}

我不确定这是否比Java 8 Stream API更快,但值得一试。