ตัวอย่างโค้ด Scala และ Java ที่โค้ด Scala ดูง่ายกว่า / มีจำนวนบรรทัดน้อยกว่า?


95

ฉันต้องการตัวอย่างโค้ด (และฉันก็อยากรู้เกี่ยวกับพวกเขาด้วย) ของโค้ด Scala และ Java ซึ่งแสดงให้เห็นว่าโค้ด Scala นั้นเรียบง่ายและรัดกุมกว่าโค้ดที่เขียนด้วย Java (แน่นอนว่าทั้งสองตัวอย่างควรแก้ปัญหาเดียวกัน)

หากมีเพียงตัวอย่าง Scala ที่มีความคิดเห็นเช่น "นี่คือโรงงานนามธรรมใน Scala ใน Java มันจะดูยุ่งยากกว่านี้" ก็ยอมรับเช่นกัน

ขอบคุณ!

ฉันชอบคำตอบที่ได้รับการยอมรับและคำตอบนี้มากที่สุด


3
ด้วยการทำงานขาเล็กน้อยคุณอาจพบตัวอย่างมากมายที่rosettacode.org
nicerobot

4
คำถามประเภทนี้จะมีคำตอบที่ถูกต้องได้อย่างไร
polygenelubricants

@polygenelubricants: แล้วคุณจะแนะนำอย่างไร?
โรมัน

10
@ โรมัน: เราคาดหวังว่าสกาล่าจะรัดกุมมากขึ้น มันจะน่าสนใจกว่านี้ถ้าคุณสามารถค้นหาสิ่งที่แสดงออกใน Java ได้อย่างกระชับมากกว่าใน Scala
Randall Schulz

1
@Randall Schulz: ทุกคนรู้ดีว่า Scala มีความกระชับมากกว่า แต่บางครั้งในทางวิชาการเราต้องการหลักฐานพร้อมตัวอย่างและทฤษฎีเบื้องหลัง
โรมัน

คำตอบ:


77

มาปรับปรุงตัวอย่างของ stackerและใช้case classของ Scala :

case class Person(firstName: String, lastName: String)

คลาส Scala ด้านบนประกอบด้วยคุณสมบัติทั้งหมดของคลาส Java ด้านล่างและอื่น ๆ อีกมากมายเช่นรองรับการจับคู่รูปแบบ (ซึ่ง Java ไม่มี) Scala 2.8 เพิ่มอาร์กิวเมนต์ที่มีชื่อและดีฟอลต์ซึ่งใช้ในการสร้างวิธีการคัดลอกสำหรับคลาสเคสซึ่งให้ความสามารถเช่นเดียวกับเมธอด with * ของคลาส Java ต่อไปนี้

public class Person implements Serializable {
    private final String firstName;
    private final String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Person withFirstName(String firstName) {
        return new Person(firstName, lastName);
    }

    public Person withLastName(String lastName) {
        return new Person(firstName, lastName);
    }

    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Person person = (Person) o;
        if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) {
            return false;
        }
        if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) {
            return false;
        }
        return true;
    }

    public int hashCode() {
        int result = firstName != null ? firstName.hashCode() : 0;
        result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
        return result;
    }

    public String toString() {
        return "Person(" + firstName + "," + lastName + ")";
    }
}

จากนั้นในการใช้งานเรามี (แน่นอน):

Person mr = new Person("Bob", "Dobbelina");
Person miss = new Person("Roberta", "MacSweeney");
Person mrs = miss.withLastName(mr.getLastName());

ต่อต้าน

val mr = Person("Bob", "Dobbelina")
val miss = Person("Roberta", "MacSweeney")
val mrs = miss copy (lastName = mr.lastName)

2
ใน 2.7.x และ 2.8.0 มีการชกมวยเพียงรายการเดียวที่อยู่ในproductElementsและunapplyไม่ได้อยู่ในตัวสร้างสนามหรือตัวเข้าถึง
retronym

2
สนับสนุนความเลวร้ายของ getter / setter ทุกประเภท ควรเพิ่มตัวตั้งค่าด้วยความไม่เต็มใจอย่างยิ่งเท่านั้นควรเพิ่มตัวรับหากจำเป็นเท่านั้น ตัวอย่างที่ดีว่าการเพิ่ม "ความเรียบง่าย" นำไปสู่นิสัยที่ไม่ดีได้อย่างไร
Bill K

7
@ บิล K: ตกลงแล้วเราจะมี case class Person(val firstName: String, val lastName: String) อะไรกัน? การทำให้สิ่งนั้นเป็นส่วนตัวก็เป็นไปได้เช่นกัน แต่ก็ไม่สมเหตุสมผลเพราะไม่ได้สมัคร ฯลฯ
soc

1
@shiva case class Person(private val firstName: String)แต่คุณไม่ควรใช้คลาสเคสแล้ว แทนที่จะทำclass Person(firstName: String)และfirstNameเป็นแบบส่วนตัวโดยค่าเริ่มต้น
nilskp

1
@shiva ไม่ความแตกต่างระหว่างvalและprivate valก็คือไม่ว่าจะเป็นวิธีการเข้าถึงเช่นfirstName()และfirstName(String)เป็นแบบสาธารณะหรือส่วนตัว ในช่อง Scala จะเป็นแบบส่วนตัวเสมอ สำหรับ Scala ในการสร้างเมธอด get / set สไตล์ Java (นอกเหนือจากตัวเข้าถึงสไตล์ Scala) จะมี@BeanPropertyคำอธิบายประกอบ
Esko Luontola

45

เจออันนี้ประทับใจ

Java

public class Person {
    private final String firstName;
    private final String lastName;
    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    public String getFirstName() {
        return firstName;
    }
    public String getLastName() {
        return lastName;
    }
}

สกาล่า

class Person(val firstName: String, val lastName: String)

เช่นเดียวกับสิ่งเหล่านี้ (ขออภัยที่ไม่ได้วางฉันไม่ต้องการขโมยรหัส)


โค้ดสกาล่านี้จะไม่สร้างgetFirstNameและgetLastNameวิธีการ คุณต้องใส่คำอธิบายประกอบพารามิเตอร์ด้วยscala.reflect.BeanPropertyคำอธิบายประกอบจึงจะทำได้
Abhinav Sarkar

7
@ abhin4v: ใช่ แต่การประชุมโค้ดใน Scala คือไม่มีตัวเข้าถึงที่นำหน้าด้วยget. Idiomatic Java code จะแตกต่างจาก idiomatic Scala code บางครั้งisคำนำหน้าใช้สำหรับบูลีน davetron5000.github.com/scala-style/naming_conventions/methods/…
Esko Luontola

7
คุณสามารถทำให้ที่case classและได้รับtoString, equalsและhashCodeฟรี (และคุณยังไม่ได้มีการทำข้อโต้แย้งvalอย่างชัดเจน):case class Person(firstName: String, lastName: String)
Jesper

@shiva สำหรับcase classไม่ใช่แค่class.
nilskp

23

งาน:เขียนโปรแกรมเพื่อจัดทำดัชนีรายการคำสำคัญ (เช่นหนังสือ)

คำอธิบาย:

  • อินพุต: รายการ <String>
  • เอาท์พุท: แผนที่ <ตัวละครรายการ <สตริง>>
  • กุญแจสำคัญของแผนที่คือ 'A' ถึง 'Z'
  • แต่ละรายการในแผนที่จะเรียงลำดับ

Java:

import java.util.*;

class Main {
  public static void main(String[] args) {
    List<String> keywords = Arrays.asList("Apple", "Ananas", "Mango", "Banana", "Beer"); 
    Map<Character, List<String>> result = new HashMap<Character, List<String>>(); 
    for(String k : keywords) {   
      char firstChar = k.charAt(0);     
      if(!result.containsKey(firstChar)) {     
        result.put(firstChar, new  ArrayList<String>());   
      }     
      result.get(firstChar).add(k); 
    } 
    for(List<String> list : result.values()) {   
      Collections.sort(list); 
    }
    System.out.println(result);         
  }
}

สกาล่า:

object Main extends App {
  val keywords = List("Apple", "Ananas", "Mango", "Banana", "Beer")
  val result = keywords.sorted.groupBy(_.head)
  println(result)
}

คุณสามารถใช้ v.sorted แทน (v sortBy identity)
Eastsun

1
และด้วย Scala 2.8 คุณสามารถใช้ mapValues ​​(_.sorted) แทนแผนที่ได้ {case ... }
Alex Boisvert

10
ด้วย Java 8 รหัสเกือบจะเหมือนกับ Scalas: keywords.stream (). sorted (). collect (Collectors.groupingBy (it -> it.charAt (0))); เคล็ดลับ!
ผู้ประสานงาน

11

งาน:

คุณมีรายชื่อpeopleของวัตถุของคลาสPersonที่มีเขตข้อมูลและname ageงานของคุณคือการจัดเรียงรายการนี้เป็นครั้งแรกโดยแล้วโดยnameage

Java 7:

Collections.sort(people, new Comparator<Person>() {
  public int compare(Person a, Person b) {
    return a.getName().compare(b.getName());
  }
});
Collections.sort(people, new Comparator<Person>() {
  public int compare(Person a, Person b) {
    return Integer.valueOf(a.getAge()).compare(b.getAge());
  }
});

สกาล่า:

val sortedPeople = people.sortBy(p => (p.name, p.age))

อัปเดต

ตั้งแต่ฉันเขียนคำตอบนี้มีความคืบหน้าอยู่พอสมควร lambdas (และการอ้างอิงวิธีการ) ได้มาถึงเกาะชวาในที่สุดและพวกเขากำลังยึดครองโลก Java โดยพายุ

นี่คือลักษณะของโค้ดด้านบนกับJava 8 (สนับสนุนโดย @fredoverflow):

people.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge));

ในขณะที่รหัสนี้เกือบจะสั้น แต่ก็ไม่ได้ใช้งานได้อย่างหรูหราเหมือนกับ Scala

ในการแก้ปัญหาสกาล่าSeq[A]#sortByวิธีการรับฟังก์ชั่นA => Bที่Bจะต้องมี เป็นประเภทคลาส คิดว่าดีที่สุดของทั้งสองโลก: ชอบมันมีความหมายสำหรับประเภทที่เป็นปัญหา แต่ชอบมันขยายได้และสามารถเพิ่มย้อนหลังไปยังประเภทที่ไม่มีได้ เนื่องจาก Java ไม่มีคลาสประเภทจึงต้องทำซ้ำทุกวิธีการดังกล่าวหนึ่งครั้งสำหรับ. ตัวอย่างเช่นดูและที่นี่OrderingOrderingComparableComparatorComparableComparatorcomparingthenComparing

ประเภทคลาสอนุญาตให้เขียนกฎเช่น "ถ้า A มีคำสั่งและ B มีการสั่งซื้อดังนั้นทูเพิล (A, B) ของพวกเขาก็มีลำดับด้วยเช่นกัน" ในรหัสนั่นคือ:

implicit def pairOrdering[A : Ordering, B : Ordering]: Ordering[(A, B)] = // impl

นั่นคือวิธีที่sortByในรหัสของเราสามารถเปรียบเทียบตามชื่อและตามอายุ ความหมายเหล่านั้นจะถูกเข้ารหัสด้วย "กฎ" ข้างต้น โปรแกรมเมอร์ Scala คาดหวังโดยสังหรณ์ใจว่าจะทำงานในลักษณะนี้ ไม่มีวิธีวัตถุประสงค์พิเศษเช่นมีที่จะเพิ่มcomparingOrdering

Lambdas และการอ้างอิงวิธีการเป็นเพียงส่วนเล็ก ๆ ของภูเขาน้ำแข็งที่เป็นการเขียนโปรแกรมเชิงฟังก์ชัน :)


ไม่มี lambdas (หรืออย่างน้อยการอ้างอิงวิธีการ) เป็นคุณสมบัติที่สำคัญที่สุดที่ฉันพลาดใน Java
Petr Gladkikh

@fredoverflow ขอบคุณที่เพิ่มตัวอย่าง Java 8 มันยังคงแสดงให้เห็นว่าทำไมแนวทางของ Scala จึงเหนือกว่า ฉันจะเพิ่มอีกในภายหลัง
missingfaktor

@rakemous เพื่อนคำตอบถูกเขียนขึ้นเมื่อหกปีที่แล้ว
missingfaktor

10

งาน:

คุณมีไฟล์ XML "company.xml" ที่มีลักษณะดังนี้:

<?xml version="1.0"?>
<company>
    <employee>
        <firstname>Tom</firstname>
        <lastname>Cruise</lastname>
    </employee>
    <employee>
        <firstname>Paul</firstname>
        <lastname>Enderson</lastname>
    </employee>
    <employee>
        <firstname>George</firstname>
        <lastname>Bush</lastname>
    </employee>
</company>

คุณต้องอ่านไฟล์นี้และพิมพ์ฟิลด์firstNameและlastNameของพนักงานทั้งหมด


Java: [นำมาจากที่นี่ ]

import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XmlReader {
  public static void main(String[] args) {   
    try {
      File file = new File("company.xml");
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
      DocumentBuilder db = dbf.newDocumentBuilder();
      Document doc = db.parse(file);
      doc.getDocumentElement().normalize();
      NodeList nodeLst = doc.getElementsByTagName("employee");
      for (int s = 0; s < nodeLst.getLength(); s++) {  
        Node fstNode = nodeLst.item(s); 
        if (fstNode.getNodeType() == Node.ELEMENT_NODE) {         
          Element fstElmnt = (Element) fstNode;
          NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("firstname");
          Element fstNmElmnt = (Element) fstNmElmntLst.item(0);
          NodeList fstNm = fstNmElmnt.getChildNodes();
          System.out.println("First Name: "  + ((Node) fstNm.item(0)).getNodeValue());
          NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("lastname");
          Element lstNmElmnt = (Element) lstNmElmntLst.item(0);
          NodeList lstNm = lstNmElmnt.getChildNodes();
          System.out.println("Last Name: " + ((Node) lstNm.item(0)).getNodeValue());
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}



Scala: [ถ่ายจากที่นี่สไลด์ # 19]

import xml.XML

object XmlReader {
  def main(args: Array[String]): Unit = {
    XML.loadFile("company.xml") match {
      case <employee> { employees @ _* } </employee> => {
        for(e <- employees) {
          println("First Name: " + (e \ "firstname").text)
          println("Last Name: " + (e \ "lastname").text)
        } 
      }
    }
  }
}

[แก้ไขโดย Bill; ตรวจสอบความคิดเห็นสำหรับการสนทนา] -

อืมจะทำอย่างไรโดยไม่ตอบกลับในส่วนการตอบกลับที่ไม่ได้จัดรูปแบบ ... ฮึ่ม ฉันเดาว่าฉันจะแก้ไขคำตอบของคุณและให้คุณลบคำตอบนั้นถ้ามันทำให้คุณผิดพลาด

นี่คือวิธีที่ฉันจะทำใน Java ด้วยไลบรารีที่ดีกว่า:

public scanForEmployees(String filename) {
    GoodXMLLib source=new GoodXMLLib(filename);
    while( String[] employee: source.scanFor("employee", "firstname", "lastname") )
    {
          System.out.println("First Name: " + employee[0]);
          System.out.println("Last Name: " + employee[1]);
    }
} 

นี่เป็นเพียงการแฮ็กอย่างรวดเร็วโดยไม่มีเวทมนตร์และส่วนประกอบที่ใช้ซ้ำได้ทั้งหมด ถ้าฉันต้องการเพิ่มเวทย์มนตร์ฉันสามารถทำบางอย่างได้ดีกว่าการส่งคืนอาร์เรย์สตริงอาร์เรย์ แต่ถึงแม้ว่า GoodXMLLib นี้จะสามารถนำกลับมาใช้ใหม่ได้อย่างสมบูรณ์ พารามิเตอร์แรกของ scanFor คือส่วนพารามิเตอร์ในอนาคตทั้งหมดจะเป็นรายการที่ต้องค้นหาซึ่งมี จำกัด แต่อินเทอร์เฟซอาจถูกบัฟเล็กน้อยเพื่อเพิ่มการจับคู่หลายระดับโดยไม่มีปัญหาจริง

ฉันจะยอมรับว่า Java มีการสนับสนุนไลบรารีที่ค่อนข้างแย่โดยทั่วไป แต่มาเพื่อเปรียบเทียบการใช้งานไลบรารี XML เก่าที่น่ากลัวของ Java (?) กับการใช้งานที่ทำโดยอิงจากการรวบรัดนั้นไม่ยุติธรรม - และอยู่ไกล จากการเปรียบเทียบภาษา!


อืมตัวอย่าง Java จะสั้นลงและดูดีขึ้นด้วยตัวแยกวิเคราะห์ SAX หรือ StAX แต่ SCALA ก็ยังดีจริงๆ
oluies

5
โค้ด Java ถูกเขียนขึ้นเพื่อแยกวิเคราะห์ไฟล์ XML นั้น ๆ โดยไม่ต้องพยายามใช้ซ้ำและโค้ดซ้ำกันจำนวนมาก ใครก็ตามที่เขียนมันอาจจะพยายามจงใจให้ดูเหมือนว่าเขาไม่เข้าใจการเข้ารหัสหรือไม่เข้าใจการเข้ารหัส
Bill K

@Bill K: ฉันไม่เคยทำการแยกวิเคราะห์ XML ใน Java ดังนั้นฉันจึงเลือกตัวอย่างนี้จากไซต์สุ่ม อย่าลังเลที่จะแก้ไขส่วน Java ของคำตอบฉันไม่รังเกียจ
missingfaktor

สมมติว่าคุณกำลังพูดถึงความแตกต่างของภาษาไม่ใช่ความแตกต่างของไลบรารี - ในกรณีนี้ทั้งสองจะเกือบเหมือนกัน ความแตกต่างของภาษาเพียงอย่างเดียวในตัวอย่างที่สองคือสิ่งที่ตรงกัน / กรณีซึ่งสามารถทำได้ในบรรทัดเดียวเป็นสำหรับลูปหากใช้ไลบรารี
Bill K

@ บิล K: ไม่คุณผิดเต็ม ๆ มีคุณลักษณะ Scala ที่ทรงพลังมากสองประการในการทำงานที่นี่: 1. XML Literals 2. Pattern Matching Java ไม่มีสิ่งเหล่านี้ ดังนั้นโค้ด Java ที่เทียบเท่าที่เขียนในไลบรารีสมมุติบางอย่างจะไม่เหมือนกัน (ลองเขียนดูสิ)
missingfaktor

10

แผนผังการดำเนินการขึ้นอยู่กับสตริง

Java 7:

// strategy pattern = syntactic cruft resulting from lack of closures
public interface Todo {   
  public void perform();
}

final Map<String, Todo> todos = new HashMap<String,Todo>();
todos.put("hi", new Todo() { 
    public void perform() { 
        System.out.println("Good morning!");
    } 
} );

final Todo todo = todos.get("hi");
if (todo != null)
    todo.perform();
else
    System.out.println("task not found");

สกาล่า:

val todos = Map( "hi" -> { () => println("Good morning!") } )
val defaultFun = () => println("task not found")
todos.getOrElse("hi", defaultFun).apply()

และทุกอย่างทำได้ในรสชาติที่ดีที่สุด!

Java 8:

Map<String, Runnable> todos = new HashMap<>();
todos.put("hi", () -> System.out.println("Good morning!"));
Runnable defaultFun = () -> System.out.println("task not found");
todos.getOrDefault("hi", defaultFun).run();

@ Rahul G ฉันคิดว่าการแก้ไขของคุณไม่ถูกต้อง todos.get("hi")ผลตอบแทนOption[()=>Unit]ที่จำเป็นในการจับคู่อย่างถูกต้อง
huynhjl

@huynhjl ฉันไม่ดี รีดกลับ
missingfaktor

3
อาจจะสั้นกว่านี้:val defaultFun = {() => println("task not found")}; todos.getOrElse("hi", defaultFun).apply()
Geoff Reedy

2
ยิ่งสั้น: val todos = Map("hi" -> { () => println("Good morning!") }) withDefaultValue { () => println("task not found") }แล้วtodos("hi")()
Martin Ring

8

ฉันชอบตัวอย่างง่ายๆของการเรียงลำดับและการเปลี่ยนแปลงที่นำมาจากหนังสือ 'Beginning Scala' ของ David Pollak:

ใน Scala:

def validByAge(in: List[Person]) = in.filter(_.valid).sortBy(_.age).map(_.first)
case class Person(val first: String, val last: String, val age: Int) {def valid: Boolean = age > 18}
validByAge(List(Person("John", "Valid", 32), Person("John", "Invalid", 17), Person("OtherJohn", "Valid", 19)))

ใน Java:

public static List<String> validByAge(List<Person> in) {
   List<Person> people = new ArrayList<Person>();
   for (Person p: in) {
     if (p.valid()) people.add(p);
   }
   Collections.sort(people, new Comparator<Person>() {
      public int compare(Person a, Person b) {
        return a.age() - b.age();
      } 
   } );
   List<String> ret = new ArrayList<String>();
     for (Person p: people) {
       ret.add(p.first);
     }
   return ret;
}

public class Person {
    private final String firstName;
    private final String lastName;
    private final Integer age;
    public Person(String firstName, String lastName, Integer age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    public String getFirst() {
        return firstName;
    }
    public String getLast() {
        return lastName;
    }
    public Integer getAge() {
       return age;
    }
    public Boolean valid() {
       return age > 18;
    }
}

List<Person> input = new ArrayList<Person>();
input.add(new Person("John", "Valid", 32));
input.add(new Person("John", "InValid", 17));
input.add(new Person("OtherJohn", "Valid", 19));

List<Person> output = validByAge(input)

8

ตอนนี้ฉันกำลังเขียนเกม Blackjack ใน Scala นี่คือวิธีที่เมธอด DealerWins ของฉันจะปรากฏใน Java:

boolean dealerWins() {
    for(Player player : players)
        if (player.beats(dealer))
            return false;
    return true;
}

นี่คือลักษณะที่ปรากฏใน Scala:

def dealerWins = !(players.exists(_.beats(dealer)))

ไชโยสำหรับฟังก์ชั่นที่สูงกว่า!

โซลูชัน Java 8:

boolean dealerWins() {
    return players.stream().noneMatch(player -> player.beats(dealer));
}

สกาลามีไวยากรณ์ที่ยากมาก ต้องจำให้มาก :-(
AZ_

Scala เป็นเหมือน CSS คุณสมบัติและคุณสมบัติมากมายที่ต้องจำ
AZ_

1
ดีกว่า:def dealerWins = !(players exists (_ beats dealer))
Kevin Wright

6

Quicksort ล่ะ?


Java

ต่อไปนี้เป็นตัวอย่าง java ที่พบจากการค้นหาของ Google

URL คือhttp://www.mycstutorials.com/articles/sorting/quicksort

public void quickSort(int array[]) 
// pre: array is full, all elements are non-null integers
// post: the array is sorted in ascending order
{
   quickSort(array, 0, array.length - 1);   // quicksort all the elements in the array
}


public void quickSort(int array[], int start, int end)
{
   int i = start;      // index of left-to-right scan
   int k = end;        // index of right-to-left scan

   if (end - start >= 1)               // check that there are at least two elements to sort
   {
       int pivot = array[start];       // set the pivot as the first element in the partition

       while (k > i)                   // while the scan indices from left and right have not met,
       {
           while (array[i] <= pivot && i <= end && k > i) // from the left, look for the first
              i++;                                        // element greater than the pivot
           while (array[k] > pivot && k >= start && k >= i) // from the right, look for the first
              k--;                                          // element not greater than the pivot
           if (k > i)                  // if the left seekindex is still smaller than
               swap(array, i, k);      // the right index, swap the corresponding elements
       }
       swap(array, start, k);          // after the indices have crossed, swap the last element in
                                       // the left partition with the pivot 
       quickSort(array, start, k - 1); // quicksort the left partition
       quickSort(array, k + 1, end);   // quicksort the right partition
    }
    else // if there is only one element in the partition, do not do any sorting
    {
        return;                        // the array is sorted, so exit
    }
}

public void swap(int array[], int index1, int index2) 
// pre: array is full and index1, index2 < array.length
// post: the values at indices 1 and 2 have been swapped
{
   int temp      = array[index1];      // store the first value in a temp
   array[index1] = array[index2];      // copy the value of the second into the first
   array[index2] = temp;               // copy the value of the temp into the second
}

สกาล่า

ความพยายามอย่างรวดเร็วในเวอร์ชัน Scala เปิดฤดูกาลสำหรับโปรแกรมปรับปรุงโค้ด; @)

def qsort(l: List[Int]): List[Int] = {
  l match {
    case Nil         => Nil
    case pivot::tail => qsort(tail.filter(_ < pivot)) ::: pivot :: qsort(tail.filter(_ >= pivot))
  }
}

1
Quicksort ในรายการที่เชื่อมโยงมีความซับซ้อนของเวลา O (n ^ 2) หรือไม่? โดยปกติจะใช้การผสานหรือคล้ายกันสำหรับรายการที่เชื่อมโยง
Esko Luontola

3
นอกจากนี้ยังไม่ใช้หางซ้ำและด้วยเหตุนี้จึงไม่เหมาะสมเป็นอัลกอริทึมที่มีประสิทธิภาพ (หรืออันที่จะไม่ล้นสแต็ก)
oxbow_lakes

ขอบคุณสำหรับความคิดเห็นที่เป็นประโยชน์ ฉันเคยเห็น Quicksort เขียนแบบนี้ที่ไหนสักแห่งและประทับใจในความกะทัดรัดเห็นได้ชัดว่าฉันไม่ได้คำนึงถึงมันมากนัก ฉันถูกเปรียบเทียบโดย LOC ซึ่งเป็นสิ่งที่น่าดึงดูดใจเสมอกับ Scala v Java
Don Mackenzie

2
Quicksort ไม่ใช่O (n ^ 2)ในรายการการทำงาน แต่แน่นอนว่ามีอันตราย โดยไม่แสดงอาการมันยังคงเป็นค่าเฉลี่ยO (n log n)แต่มีความเป็นไปได้ทางสถิติสูงกว่าที่จะกดปุ่มO (n ^ 2) ที่เลวร้ายที่สุดเนื่องจากเราเลือกจุดหมุนที่ส่วนหัวของรายการเสมอแทนที่จะเลือกแบบสุ่ม .
Daniel Spiewak

การกรองสองครั้งไม่ดี ดูในคำตอบของฉันสำหรับคำถามของคุณการใช้partitionเพื่อหลีกเลี่ยงสิ่งนั้น
Daniel C. Sobral

6

ฉันชอบคำตอบของผู้ใช้ที่ไม่รู้จัก มากฉันจะพยายามปรับปรุงให้ดีขึ้น โค้ดด้านล่างไม่ใช่การแปลตัวอย่าง Java โดยตรง แต่จะทำงานเดียวกันให้สำเร็จด้วย API เดียวกัน

def wordCount (sc: Scanner, delimiter: String) = {
  val it = new Iterator[String] {
    def next = sc.nextLine()
    def hasNext = sc.hasNextLine()
  }
  val words = it flatMap (_ split delimiter iterator)
  words.toTraversable groupBy identity mapValues (_.size)
}

ตอนนี้ฉันไม่ได้ติดตั้ง scala-2.8 เพื่อทดสอบตัวอย่างข้อมูลนี้ แต่ฉันเดาว่าฉันสามารถเห็นสิ่งที่เป็นจุดมุ่งหมาย - ไม่ได้ใช้แค่ 'คำหลัก' มันสร้างแผนที่ของสตริงและความถี่ทั้งหมดใช่หรือไม่?
ไม่ทราบผู้ใช้

@user ใช่นั่นคือสิ่งที่ทำ รหัสของคุณสำเร็จแล้วไม่ใช่เหรอ อ้อเข้าใจแล้ว. ฉันคัดลอกบรรทัดผิด ฉันจะแก้ไขทันที :-)
Daniel C. Sobral

6

ฉันชอบเมธอด getOrElseUpdate มากที่พบใน mutableMap และแสดงที่นี่ Java ตัวแรกโดยไม่มี:

public static Map <String, Integer> wordCount (Scanner sc, String delimiters) {
    Map <String, Integer> dict = new HashMap <String, Integer> ();
            while (sc.hasNextLine ()) {
                    String[] words = sc.nextLine ().split (delimiters);
                    for (String word: words) {
                        if (dict.containsKey (word)) {
                            int count = dict.get (word);
                            dict.put (word, count + 1);
                        } else
                            dict.put (word, 1);
                    }
            }       
    return dict;
}

ใช่ - WordCount และที่นี่ใน scala:

def wordCount (sc: Scanner, delimiter: String) = {
        val dict = new scala.collection.mutable.HashMap [String, Int]()
        while (sc.hasNextLine ()) {
                val words = sc.nextLine.split (delimiter)
                words.foreach (word =>
                      dict.update (word, dict.getOrElseUpdate (word, 0) + 1))
        }
        dict
}

และนี่คือใน Java 8:

public static Map<String, Integer> wordCount(Scanner sc, String delimiters)
{
    Map<String, Integer> dict = new HashMap<>();
    while (sc.hasNextLine())
    {
        String[] words = sc.nextLine().split(delimiters);
        Stream.of(words).forEach(word -> dict.merge(word, 1, Integer::sum));
    }
    return dict;
}

และหากคุณต้องการใช้งานได้ 100%:

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.*;

public static Map<String, Long> wordCount(Scanner sc, String delimiters)
{
    Stream<String> stream = stream(sc.useDelimiter(delimiters));
    return stream.collect(groupingBy(identity(), counting()));
}

public static <T> Stream<T> stream(Iterator<T> iterator)
{
    Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize(iterator, 0);
    return StreamSupport.stream(spliterator, false);
}

filterและsortได้แสดงไปแล้ว แต่ดูง่ายแค่ไหนที่รวมเข้ากับแผนที่:

    def filterKeywords (sc: Scanner, keywords: List[String]) = {
            val dict = wordCount (sc, "[^A-Za-z]")
            dict.filter (e => keywords.contains (e._1)).toList . sort (_._2 < _._2)
    } 

ฉันชอบตัวอย่างนี้มาก หลีกเลี่ยงเส้นทางที่ง่ายในการเปรียบเทียบคลาสเคสและไม่ทำให้เกิดข้อผิดพลาดในการแสดงโค้ด Scala และไม่เทียบเท่ากับ Java
Daniel C. Sobral

5

นี่เป็นตัวอย่างที่ง่ายมาก: จำนวนเต็มกำลังสองแล้วบวกเข้าไป


    public int sumSquare(int[] list) {
        int s = 0;
        for(int i = 0; i < list.length; i++) {
            s += list[i] * list[i]; 
        }
        return s;
    }

ใน scala:


val ar = Array(1,2,3)
def square(x:Int) = x * x
def add(s:Int,i:Int) = s+i

ar.map(square).foldLeft(0)(add)

Compact map ใช้ฟังก์ชันกับองค์ประกอบทั้งหมดของอาร์เรย์ดังนั้น:

Array(1,2,3).map(square)
Array[Int] = Array(1, 4, 9)

พับซ้ายจะเริ่มต้นด้วย 0 เป็นตัวสะสมและใช้add(s,i)กับองค์ประกอบทั้งหมด (i) ของอาร์เรย์เพื่อให้:

 Array(1,4,9).foldLeft(0)(add)  // return 14 form 0 + 1 + 4 + 9

ตอนนี้สามารถบีบอัดเพิ่มเติมเพื่อ:

Array(1,2,3).map(x => x * x ).foldLeft(0)((s,i) => s + i )

อันนี้ฉันจะไม่ลองใน Java (ใช้งานได้มาก) เปลี่ยน XML เป็นแผนที่:


<a>
   <b id="a10">Scala</b>
   <b id="b20">rules</b>
</a>

อีกหนึ่งซับเพื่อรับแผนที่จาก XML:


val xml = <a><b id="a10">Scala</b><b id="b20">rules</b></a>

val map = xml.child.map( n => (n \ "@id").text -> n.child.text).toMap
// Just to dump it.
for( (k,v) <- map) println(k + " --> " + v)

ปัญหาของคุณsumSquareใน Scala คือมันดูคลุมเครือมากสำหรับนักพัฒนา Java ซึ่งจะให้กระสุนกับคุณเพื่อบ่นว่า Scala คลุมเครือและซับซ้อน ...
Jesper

ฉันจัดรูปแบบใหม่เล็กน้อยเพื่อปรับปรุงตัวอย่าง หวังว่าเรื่องนี้จะไม่ทำร้ายสกาล่า
Thomas

5
scala> 1 ถึง 10 map (x => x * x) sum res0: Int = 385 มาดูนักพัฒนา java เรียกว่า cryptic เมื่อถึงจุดนั้นมันก็เป็นนิ้วที่อยู่ในหูและพูดว่า nah-nah-nah
psp

3
@Jesper สำหรับนักพัฒนาที่ไม่ใช่ Java Java ดูเหมือนว่ามีแผ่นสำเร็จรูปและสัญญาณรบกวนจำนวนมาก นั่นไม่ได้หมายความว่าคุณจะทำงานจริงในภาษาไม่ได้
James Moore

คุณสามารถใช้ reduceLeft (เพิ่ม) แทน foldLeft (0) (เพิ่ม) ฉันคิดว่ามันง่ายกว่าที่จะอ่านเมื่อองค์ประกอบเริ่มต้นของคุณเป็นองค์ประกอบศูนย์ / เอกลักษณ์ของกลุ่ม
Debilski

5

ปัญหา:คุณต้องออกแบบวิธีการที่จะรันโค้ดที่กำหนดแบบอะซิงโครนัส

โซลูชันในJava :

/**
* This method fires runnables asynchronously
*/
void execAsync(Runnable runnable){
    Executor executor = new Executor() {
        public void execute(Runnable r) {
            new Thread(r).start();
        }
    };
    executor.execute(runnable);
}

...

execAsync(new Runnable() {
            public void run() {
                ...   // put here the code, that need to be executed asynchronously
            }
});

สิ่งเดียวกันในScala (ใช้นักแสดง):

def execAsync(body: => Unit): Unit = {
  case object ExecAsync    
  actor {
    start; this ! ExecAsync
    loop {
      react {           
        case ExecAsync => body; stop
      }
    }
  }    
}

...

execAsync{  // expressive syntax - don't need to create anonymous classes
  ...  // put here the code, that need to be executed asynchronously    
}

6
ณ วันที่ 2.8 สิ่งนี้สามารถเขียนเป็น Futures.future {body} และมีประสิทธิภาพมากกว่าเนื่องจากอนาคตที่ส่งกลับมาโดยสามารถรวมเข้าด้วยกันเพื่อให้ได้มูลค่าที่ประเมินได้ในที่สุด
Dave Griffith

3

รูปแบบ Circuit Breaker จากRelease It ของ Michael NygardในFaKods ( ลิงก์ไปยังรหัส )

การใช้งานมีลักษณะเช่นนี้ใน Scala:

. . .
addCircuitBreaker("test", CircuitBreakerConfiguration(100,10))
. . .


class Test extends UsingCircuitBreaker {
  def myMethodWorkingFine = {
    withCircuitBreaker("test") {
      . . .
    }
  }

  def myMethodDoingWrong = {
    withCircuitBreaker("test") {
      require(false,"FUBAR!!!")
    }
  }
}

ซึ่งฉันคิดว่าดีมาก มันดูเป็นภาษาที่ไม่เหมือนใคร แต่มันเป็นมิกซ์อินง่ายๆในCircuitBreaker Object ที่ทำงานทั้งหมด

/**
 * Basic MixIn for using CircuitBreaker Scope method
 *
 * @author Christopher Schmidt
 */
trait UsingCircuitBreaker {
  def withCircuitBreaker[T](name: String)(f: => T): T = {
    CircuitBreaker(name).invoke(f)
  }
}

การอ้างอิงในภาษาอื่น ๆ ของ Google สำหรับ "เบรกเกอร์" + ภาษาของคุณ


3

ฉันกำลังเตรียมเอกสารที่ให้ตัวอย่างโค้ด Java และ Scala หลายอย่างโดยใช้เฉพาะคุณสมบัติที่เข้าใจง่ายของ Scala:

Scala: Java ที่ดีกว่า

หากคุณต้องการให้ฉันเพิ่มอะไรเข้าไปโปรดตอบกลับในความคิดเห็น


หัวข้อ "Scala: A better Java" is missleading
duckhunt

2

กระแสที่ไม่สิ้นสุดที่ประเมินอย่างเกียจคร้านเป็นตัวอย่างที่ดี:

object Main extends Application {

   def from(n: Int): Stream[Int] = Stream.cons(n, from(n + 1))

   def sieve(s: Stream[Int]): Stream[Int] =
     Stream.cons(s.head, sieve(s.tail filter { _ % s.head != 0 }))

   def primes = sieve(from(2))

   primes take 10 print

}

นี่คือคำถามเกี่ยวกับสตรีมที่ไม่มีที่สิ้นสุดใน Java: ตัววนซ้ำแบบอนันต์ออกแบบไม่ดีหรือไม่?

อีกตัวอย่างที่ดีคือฟังก์ชันชั้นหนึ่งและการปิด:

scala> def f1(w:Double) = (d:Double) => math.sin(d) * w
f1: (w: Double)(Double) => Double

scala> def f2(w:Double, q:Double) = (d:Double) => d * q * w
f2: (w: Double,q: Double)(Double) => Double

scala> val l = List(f1(3.0), f2(4.0, 0.5))
l: List[(Double) => Double] = List(<function1>, <function1>)

scala> l.map(_(2))
res0: List[Double] = List(2.727892280477045, 4.0)

Java ไม่รองรับฟังก์ชันระดับเฟิร์สคลาสและการเลียนแบบการปิดด้วยคลาสภายในแบบไม่ระบุตัวตนนั้นไม่ได้ดูหรูหรามากนัก อีกสิ่งหนึ่งในตัวอย่างนี้แสดงให้เห็นว่า java ไม่สามารถทำได้คือการเรียกใช้โค้ดจาก interpreter / REPL ฉันพบว่าสิ่งนี้มีประโยชน์อย่างมากสำหรับการทดสอบข้อมูลโค้ดอย่างรวดเร็ว


โปรดทราบว่าตะแกรงช้าเกินไปที่จะใช้งานได้จริง
Elazar Leibovich

@oxbow_lakes ไม่มี java ที่เทียบเท่าสำหรับตัวอย่างเหล่านี้
dbyrne

@dbyme ไม่จริง. คุณสามารถ subclass Java IterableและIteratorสร้างสตรีมที่ไม่มีที่สิ้นสุดได้อย่างง่ายดาย
Daniel C. Sobral

@dbyrne "อีกสิ่งหนึ่งที่ตัวอย่างนี้แสดงให้เห็นว่า java ไม่สามารถทำได้คือการเรียกใช้โค้ดจากล่าม / REPL ฉันพบว่าสิ่งนี้มีประโยชน์อย่างมากสำหรับการทดสอบตัวอย่างโค้ดอย่างรวดเร็ว" ฉันใช้หน้าสมุดเรื่องที่สนใจใน Eclipse เพื่อลองใช้ข้อมูลโค้ด Java การทำส่วนใหญ่ถ้าไม่ใช่ Java ทั้งหมดทำงานใน IDE นั้นฉันไม่ต้องการ REPL ฉันใช้ notepad.exe และ javac ในช่วงแรก ๆ เมื่อฉันไม่แน่ใจเกี่ยวกับคุณสมบัติของภาษาหรือไลบรารีและหลังจากนั้นไม่นานมันก็ทำงานได้ดีและรวดเร็ว - แม้ว่า REPL จะค่อนข้างใช้งานง่ายกว่าและเร็วกว่าก็ตาม ฉันสามารถหลีกเลี่ยงการแฮ็กแผ่นจดบันทึกได้โดยการติดตั้ง VisualAge ที่เรามีอยู่แล้ว

2

ทำไมไม่มีใครโพสต์สิ่งนี้มาก่อน:

Java:

class Hello {
     public static void main( String [] args ) {
          System.out.println("Hello world");
     }
}

116 อักขระ

สกาล่า:

object Hello extends App {
     println("Hello world")
}

56 อักขระ


1
Applicationลักษณะที่ถือว่าเป็นอันตราย ... scala-blogs.org/2008/07/…
missingfaktor

0

รหัสสกาล่านี้ ...

def partition[T](items: List[T], p: (T, T) => Boolean): List[List[T]] = {
  items.foldRight[List[List[T]]](Nil)((item: T, items: List[List[T]]) => items match {
    case (first :: rest) :: last if p (first, item) =>
      (List(item)) :: (first :: rest) :: last
    case (first :: rest) :: last =>
      (item :: first :: rest) :: last
    case _ => List(List(item))
  })
}

... จะไม่สามารถอ่านได้อย่างสมบูรณ์ใน Java ถ้าเป็นไปได้เลย


10
OPINIO ที่ถูกต้องของฉัน: ขอบคุณสำหรับคำตอบ! แต่คุณช่วยอธิบายได้ไหมว่าเกิดอะไรขึ้นที่นั่น? ฉันยังไม่คุ้นเคยกับไวยากรณ์ของ Scala และ (นั่นเป็นเหตุผลที่เป็นไปได้ว่าทำไม) มันดูไม่สามารถอ่านได้อย่างสมบูรณ์สำหรับฉันในตอนนี้
Roman

เป็นการแบ่งรายการทั่วไปของประเภท T โดยใช้ฟังก์ชันการแบ่งพาร์ติชันที่จัดเตรียมไว้เป็นตัวป้องกันในรูปแบบการจับคู่ประโยคของคำสั่ง case
เพียงแค่ความคิดเห็นที่ถูกต้องของฉัน

3
แปลก. ฉันไม่ได้เป็นผู้เชี่ยวชาญ Scala จากระยะไกลและสามารถเข้าใจได้
เพียงความคิดเห็นที่ถูกต้องของฉัน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.