我有一個包含 SW 字符的 csv 檔案,并且想使用 java 流找到最重的字符。這是該檔案的示例:
name;height;mass;hair_color;skin_color;eye_color;birth_year;gender
Luke Skywalker;172;77;blond;fair;blue;19BBY;male
C-3PO;167;75;n/a;gold;yellow;112BBY;n/a
R2-D2;96;32;n/a;white, blue;red;33BBY;n/a
Darth Vader;202;136;none;white;yellow;41.9BBY;male
Leia Organa;150;49;brown;light;brown;19BBY;female
Owen Lars;178;120;brown, grey;light;blue;52BBY;male
Beru Whitesun lars;165;75;brown;light;blue;47BBY;female
Grievous;216;159;none;brown, white;green, yellow;unknown;male
Finn;unknown;unknown;black;dark;dark;unknown;male
Rey;unknown;unknown;brown;light;hazel;unknown;female
Poe Dameron;unknown;unknown;brown;light;brown;unknown;male
預期輸出是字串“Grievous”。
最初我想創建一個 Character 類,我可以在其中存盤資料并在分割線后使用物件而不是 String 陣列。但是,每個值都可能未知或不適用,因此不太確定如何解決它。有沒有辦法只使用流來實作這一點?
這是我最初的嘗試,將每一行映射到Person帶有欄位name和的新物件height,但是這種方法不能正確處理未知輸入。
public static String getHeaviestCharacter(String file) throws IOException {
return Files.lines(Paths.get(file))
.map(line -> line.split(";"))
.map(part -> new Person(part[0], part[2]))
.max((p1, p2) -> Integer.compare(p1.getWeight(), p2.getWeight()))
.map(p1.getName());
}
uj5u.com熱心網友回復:
流
正如其他人指出的那樣,我懷疑流是解決您的特定問題的最佳方法。但是既然你問了,只是為了好玩,我試了一下。經過大量的網路搜索和反復試驗,我似乎找到了使用流的解決方案。
我們使用NIO.2類Path&Files打開資料檔案。
我們通過呼叫來定義一個流Files.lines。
我們通過呼叫省略標題行Stream#skip。
您的某些輸入行在我們的目標第三欄位中具有非數字值“未知”。所以我們呼吁Stream#filter忽略這些行。String#split我們通過使用同時傳遞煩人的從零開始的索引號來提取第三個欄位2。
要獲得第三列中的最高數字,我們需要進行排序。Comparator為了排序,我們在創建的 via中提取第三個欄位Comparator.comparingInt。為了獲得所需的int值,我們使用 決議第三個欄位的文本Integer.parseInt。
排序后,我們需要訪問流中的最后一個元素,因為那應該是我們的字符權重最大的元素。這對我來說似乎很笨拙,但顯然獲取流的最后一個元素的方法是.reduce( ( first , second ) -> second ).orElse( null ). 我當然希望我們有一個Stream#last方法!
最后一個元素是一個String物件,即輸入檔案中的一行文本。所以我們需要再次拆分字串。但是這次我們拆分時,我們取第一個元素而不是第三個,因為我們的目標是報告角色的名字。第一個元素由煩人的從零開始的索引號標識0。
瞧,我們得到Grievous了最終結果。
Path path = Paths.get( "/Users/basil_dot_work/inputs.csv" );
if ( Files.notExists( path ) ) { throw new IllegalStateException( "Failed to find file at path: " path ); }
Stream < String > lines;
try { lines = Files.lines( path , StandardCharsets.UTF_8 ); } catch ( IOException e ) { throw new RuntimeException( e ); }
String result =
lines
.skip( 1L ) // Skip the header row, with column names.
.filter( // Filter out lines whose targeted value is "unknown". We need text made up only of digits.
line -> ! line.split( ";" )[ 2 ].equalsIgnoreCase( "unknown" )
)
.sorted( // Sort by extracting third field’s text, then parse to get an `int` value.
Comparator.comparingInt( ( String line ) -> Integer.parseInt( line.split( ";" )[ 2 ] ) )
)
.reduce( ( first , second ) -> second ).orElse( null ) // Get last element.
.split( ";" )[ 0 ]; // Extract name of character from first field of our one and only line of input left remaining after processing.
System.out.println( "result = " result );
結果=嚴重
請務必將我的方法與Florian Hartung 的另一個答案進行比較。另一個可能會更好。我還沒有仔細研究過。
沒有流
為了比較,這里是更傳統的代碼,很少或沒有使用流。
我們以與上面相同的方式從檔案中讀取行。
我們需要跳過第一行,即列標題的標題行。但是List回傳的物件Files.lines是不可修改的。所以我們不能簡單地洗掉該串列的第一個元素。所以我們通過呼叫有效地跳過了第一行lines.subList( 1 , lines.size() )。該subList命令回傳一個串列,該串列作為視圖映射回原始串列,而不是實際創建新的單獨串列。這是有效的,適合我們在這里使用。
我們定義一個類作為記錄來保存每個人的詳細資訊。我們使用Integer而不是int,以便我們可以null為帶有unknown文本而不是數字的行保存a。
對于每一行,我們直接將文本項傳輸到String成員欄位。但是對于高度和質量,我們使用三元運算子來回傳null或實體化一個Integer物件。
Person我們通過添加到串列來收集我們的物件。
為了得到最大的Person物件的mass最大值,我們需要忽略那些帶有null. 所以我們在這里使用一個簡單的流來創建Person具有非空質量的新物件串列。這個流可以用傳統的回圈代替,但會更冗長。
使用我們的過濾串列,我們Collections.max在傳遞一個比較成員欄位的Comparator物件時呼叫。mass
我們最終得到一個Person物件。所以我們查詢它的name成員欄位。
瞧,我們得到Grievous了最終結果。
Path path = Paths.get( "/Users/basil_dot_work/inputs.csv" );
if ( Files.notExists( path ) ) { throw new IllegalStateException( "Failed to find file at path: " path ); }
List < String > lines;
try { lines = Files.lines( path , StandardCharsets.UTF_8 ).toList(); } catch ( IOException e ) { throw new RuntimeException( e ); }
lines = lines.subList( 1 , lines.size() ); // Skip over first line.
record Person( String name , Integer height , Integer mass , String hair_color , String skin_color , String eye_color , String birth_year , String gender ) { }
List < Person > persons = new ArrayList <>();
for ( String line : lines )
{
String[] parts = line.split( ";" );
Integer height = ( parts[ 1 ].equalsIgnoreCase( "unknown" ) ) ? null : Integer.valueOf( parts[ 1 ] );
Integer mass = ( parts[ 2 ].equalsIgnoreCase( "unknown" ) ) ? null : Integer.valueOf( parts[ 2 ] );
Person person = new Person( parts[ 0 ] , height , mass , parts[ 3 ] , parts[ 4 ] , parts[ 5 ] , parts[ 6 ] , parts[ 7 ] );
persons.add( person );
}
System.out.println( "persons = " persons );
List < Person > personsWithMass = persons.stream().filter( person -> Objects.nonNull( person.mass ) ).toList();
Person heaviestPerson = Collections.max( personsWithMass , Comparator.comparing( person -> person.mass ) );
System.out.println( "heaviest Person’s name = " heaviestPerson.name );
最重的人的名字=Grievous
uj5u.com熱心網友回復:
我不建議使用 Streams 執行此操作,而是使用一些 CSV 庫,因為它更安全。
public static void main(String[] args) {
try {
BufferedReader reader = new BufferedReader(new FileReader(new File("characters.csv")));
// Skip first line
reader.readLine();
Optional<String> optionalHeaviestCharacter = getHeaviestCharactersName(reader.lines());
System.out.println(optionalHeaviestCharacter);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Optional<String> getHeaviestCharactersName(Stream<String> lineStream) {
return lineStream
.map(lineString -> lineString.split(";")) // map every line string to an array with all values
.filter(values -> values[2].matches("[0-9] ")) // filter out characters with a non-number value as a mass
.max((values1, values2) -> Integer.compare(Integer.parseInt(values1[2]), Integer.parseInt(values2[2]))) // get element with maximum mass
.map(heaviestValues -> heaviestValues[0]); // map values array of heaviest character to its name
}
首先我們讀取檔案,我有名字characters.csv。您可能需要編輯檔案路徑以指向您的檔案。
BufferedReader reader = new BufferedReader(new FileReader(new File("characters.csv")));
Stream<String>然后我們通過呼叫reader.lines()方法從檔案中讀取所有行,每一行作為一個字串
然后該函式getHeaviestCharactersName將回傳一個Optional<String>. Optional 將為空,例如,當所有字符都具有未知/無效的質量或根本不存在字符時。
如果您認為總會有至少一個角色具有有效的大量存在,您將得到最重的角色的名稱optionalHeaviestCharacter.get()。否則,您必須先檢查 Optional 是否為空:
if (optionalHeaviestCharacter.isEmpty()) {
System.out.println("Could not find a character with the heaviest mass");
} else {
System.out.println("Heaviest character is " optionalHeaviestCharacter.get());
}
您可以通過呼叫來獲取名稱
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/466938.html
