有没有办法用类似于常规数组的 ArrayList 来计算字符频率?
Is there a way to count character frequency with an ArrayList similar to a regular array?
通常当你想得到一个字符的频率时,你可以这样做:
int[] count = new int[256];
for(int i: arr) count[arr.charAt(i)]++;
// Example if you have 2 'a' characters count[97] (97 being the ascii value of 'a') will return 2
有没有办法用 ArrayList 代替?
tl;博士
让我们开始使用以下代码,或者继续阅读下面的代码以获得更简单的代码。
"Hello"
.codePoints() // Returns `IntStream` of the code point for each character in the string.
.boxed() // Converts `int` primitives to `Integer` objects.
.collect(
Collectors.groupingBy(
Function.identity() , // Classification function.
TreeMap :: new , // Map factory.
Collectors.counting() // Downstream collector.
)
)
.forEach(
( codePoint , count ) ->
System.out.println( "Code point: " + codePoint + " | Character: " + Character.toString( codePoint ) + " | Count: " + count )
);
Code point: 72 | Character: H | Count: 1
Code point: 101 | Character: e | Count: 1
Code point: 108 | Character: l | Count: 2
Code point: 111 | Character: o | Count: 1
Code point: 128075 | Character: | Count: 1
列表
作为 ,您可以使用 List
实现,例如 ArrayList
。但可能没有好处。代码会更复杂,会使用更多内存,并且可能会降低性能。您将不得不使用 Integer
个对象而不是 int
个基元。
顺便说一句,你不应该使用 char
。该类型自 Java 2 以来一直是旧类型。作为 16 位值,char
在物理上无法表示大多数字符。
而且您的 256 限制太小了。 Java 支持 Unicode 中定义的所有超过 140,000 个字符。这些字符被分配给范围超过一百万的代码点整数。使用常量 Character.MAX_CODE_POINT
作为限制。
List< Integer > counts = new ArrayList<>( Character.MAX_CODE_POINT ) ;
为每个元素填充一个零。列表在每个元素中初始化为 null,这与 int
的数组在每个元素中初始化为零不同。
for( int i = 0 ; i <= Character.MAX_CODE_POINT ; i ++ )
{
counts.add( 0 ) ;
}
处理您的输入。
String input = "Hello" ;
int[] codePoints = input.codePoints().toArray() ;
for( int i = 0 ; i < codePoints.length ; i ++ )
{
int codePoint = codePoints[ i ] ;
int count = counts.get( codePoint ) ;
counts.set( codePoint , count + 1 ) ;
}
我们可以通过将 counts
列表转储到控制台来报告结果。但是如果有超过一百万个元素,那将很麻烦。相反,让我们过滤掉计数为零的所有元素。
for ( int index = 0 ; index < counts.size() ; index++ )
{
if ( counts.get( index ) != 0 )
{
System.out.println(
index + " ➣ " + counts.get( index )
);
}
}
或者,使用流和 lambda 语法执行相同的操作。保存效果。
IntStream.range( 0 , counts.size() )
.filter( index -> counts.get( index ) != 0 )
.mapToObj( index -> index + " ➣ " + counts.get( index ) )
.forEach( System.out :: println );
当运行:
72 ➣ 1
101 ➣ 1
108 ➣ 2
111 ➣ 1
128075 ➣ 1
地图
如果使用对象和集合,使用 Map
而不是 List
会更有意义。地图中的条目数与输入中的不同字母数相同,而不是列表中超过一百万个。
映射跟踪键和值对。在我们手头的问题中,我们将使用代码点编号作为我们的键,而计数将是我们的值。
如果我们想保留我们的密钥,我们的代码点,我们将使用 NavigableMap
.
String input = "Hello";
NavigableMap < Integer, Long > codePointFrequency =
input
.codePoints() // Returns `IntStream` of the code point for each character in the string.
.boxed() // Converts `int` primitives to `Integer` objects.
.collect(
Collectors.groupingBy(
Function.identity() , // Classification function.
TreeMap :: new , // Map factory.
Collectors.counting() // Downstream collector.
)
);
将地图转储到控制台。
System.out.println( "codePointFrequency = " + codePointFrequency );
当运行.
codePointFrequency = {72=1, 101=1, 108=2, 111=1, 128075=1}
报告每个字符。
codePointFrequency.forEach(
( codePoint , count ) ->
System.out.println( "Code point: " + codePoint + " | Character: " + Character.toString( codePoint ) + " | Count: " + count )
);
当运行.
Code point: 72 | Character: H | Count: 1
Code point: 101 | Character: e | Count: 1
Code point: 108 | Character: l | Count: 2
Code point: 111 | Character: o | Count: 1
Code point: 128075 | Character: | Count: 1
通常当你想得到一个字符的频率时,你可以这样做:
int[] count = new int[256];
for(int i: arr) count[arr.charAt(i)]++;
// Example if you have 2 'a' characters count[97] (97 being the ascii value of 'a') will return 2
有没有办法用 ArrayList 代替?
tl;博士
让我们开始使用以下代码,或者继续阅读下面的代码以获得更简单的代码。
"Hello"
.codePoints() // Returns `IntStream` of the code point for each character in the string.
.boxed() // Converts `int` primitives to `Integer` objects.
.collect(
Collectors.groupingBy(
Function.identity() , // Classification function.
TreeMap :: new , // Map factory.
Collectors.counting() // Downstream collector.
)
)
.forEach(
( codePoint , count ) ->
System.out.println( "Code point: " + codePoint + " | Character: " + Character.toString( codePoint ) + " | Count: " + count )
);
Code point: 72 | Character: H | Count: 1
Code point: 101 | Character: e | Count: 1
Code point: 108 | Character: l | Count: 2
Code point: 111 | Character: o | Count: 1
Code point: 128075 | Character: | Count: 1
列表
作为 List
实现,例如 ArrayList
。但可能没有好处。代码会更复杂,会使用更多内存,并且可能会降低性能。您将不得不使用 Integer
个对象而不是 int
个基元。
顺便说一句,你不应该使用 char
。该类型自 Java 2 以来一直是旧类型。作为 16 位值,char
在物理上无法表示大多数字符。
而且您的 256 限制太小了。 Java 支持 Unicode 中定义的所有超过 140,000 个字符。这些字符被分配给范围超过一百万的代码点整数。使用常量 Character.MAX_CODE_POINT
作为限制。
List< Integer > counts = new ArrayList<>( Character.MAX_CODE_POINT ) ;
为每个元素填充一个零。列表在每个元素中初始化为 null,这与 int
的数组在每个元素中初始化为零不同。
for( int i = 0 ; i <= Character.MAX_CODE_POINT ; i ++ )
{
counts.add( 0 ) ;
}
处理您的输入。
String input = "Hello" ;
int[] codePoints = input.codePoints().toArray() ;
for( int i = 0 ; i < codePoints.length ; i ++ )
{
int codePoint = codePoints[ i ] ;
int count = counts.get( codePoint ) ;
counts.set( codePoint , count + 1 ) ;
}
我们可以通过将 counts
列表转储到控制台来报告结果。但是如果有超过一百万个元素,那将很麻烦。相反,让我们过滤掉计数为零的所有元素。
for ( int index = 0 ; index < counts.size() ; index++ )
{
if ( counts.get( index ) != 0 )
{
System.out.println(
index + " ➣ " + counts.get( index )
);
}
}
或者,使用流和 lambda 语法执行相同的操作。保存效果。
IntStream.range( 0 , counts.size() )
.filter( index -> counts.get( index ) != 0 )
.mapToObj( index -> index + " ➣ " + counts.get( index ) )
.forEach( System.out :: println );
当运行:
72 ➣ 1
101 ➣ 1
108 ➣ 2
111 ➣ 1
128075 ➣ 1
地图
如果使用对象和集合,使用 Map
而不是 List
会更有意义。地图中的条目数与输入中的不同字母数相同,而不是列表中超过一百万个。
映射跟踪键和值对。在我们手头的问题中,我们将使用代码点编号作为我们的键,而计数将是我们的值。
如果我们想保留我们的密钥,我们的代码点,我们将使用 NavigableMap
.
String input = "Hello";
NavigableMap < Integer, Long > codePointFrequency =
input
.codePoints() // Returns `IntStream` of the code point for each character in the string.
.boxed() // Converts `int` primitives to `Integer` objects.
.collect(
Collectors.groupingBy(
Function.identity() , // Classification function.
TreeMap :: new , // Map factory.
Collectors.counting() // Downstream collector.
)
);
将地图转储到控制台。
System.out.println( "codePointFrequency = " + codePointFrequency );
当运行.
codePointFrequency = {72=1, 101=1, 108=2, 111=1, 128075=1}
报告每个字符。
codePointFrequency.forEach(
( codePoint , count ) ->
System.out.println( "Code point: " + codePoint + " | Character: " + Character.toString( codePoint ) + " | Count: " + count )
);
当运行.
Code point: 72 | Character: H | Count: 1
Code point: 101 | Character: e | Count: 1
Code point: 108 | Character: l | Count: 2
Code point: 111 | Character: o | Count: 1
Code point: 128075 | Character: | Count: 1