我有一个包含数千个数据的数组列表。
例如:
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列表中有非常大的数据集合。 没有使用循环有没有不同的解决方案?
感谢。
答案 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会强制您传入ExecutorService
和int
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更快,但值得一试。