繁体   English   中英

元素周期表的数据结构

[英]Data Structure of the Periodic Table of Elements

我的目标是使用元素周期表(或列表)来获取有关Java中特定元素的信息。 我想按原子序号和符号搜索它(但是转换应该很简单)。

我在此JQuery插件中找到了该信息。 但是它存储为JSON文件。

对信息进行硬编码似乎是最有效的方法(因为它不会经常更改并且由于性能原因),但是如何将JSON转换为硬编码enum呢?

以来:

  • 有关元素的信息是完全静态的
  • 每个基本符号都是字母数字
  • 发现新元素既罕见又无关紧要(因为它们极其不稳定)

枚举似乎是一个不错的选择:

public enum Element {
    H(1, "Hydrogen", 1.008, -259.1),
    He(2, "Helium", 4.003, -272.2),
    Li(3, "Lithium", 6.941, 180.5),
    // ... 90+ others
    ;

    private static class Holder {
        static Map<Integer, Element> map = new HashMap<Integer, Element>();
    }

    private final int atomicNumber;
    private final String fullName;
    private final double atomicMass;
    private final double meltingPoint;

    private Element(int atomicNumber, String fullName, double atomicMass, double meltingPoint) {
        this.atomicNumber = atomicNumber;
        this.fullName = fullName;
        this.atomicMass = atomicMass;
        this.meltingPoint = meltingPoint;
        Holder.map.put(atomicNumber, this);
    }

    public static Element forAtomicNumber(int atomicNumber) {
        return Holder.map.get(atomicNumber);
    }

    public int getAtomicNumber() {
        return atomicNumber;
    }

    public String getFullName() {
        return fullName;
    }

    public double getAtomicMass() {
        return atomicMass;
    }

    public double getMeltingPoint() {
        return meltingPoint;
    }
}

这里有一些Java功夫值得解释。 映射被放置在静态内部(所有者)类中,因此在初始化枚举实例之前对其进行了初始化,这样它们便可以将自身添加到其中。 如果不在内部静态类中,则不会进行初始化,因为在枚举类中初始化的第一件事必须是实例,但是静态内部类在初始化类之前已初始化。

这种方法意味着实例不需要以任何特定顺序列出(它们可以按字母顺序列出,或以其他方式列出)。

假设您有一个PeriodicTable.txt文件,其格式如下:

ATOMIC_NUMBER SYMBOL OTHER_INFO

喜欢:

1 H Hydrogen -> Lightest element
2 He Helium -> Second lightest element
3 Li Lithium -> Third lightest element
// and so on...

然后,您可以对自己的PeriodicTable进行相当简单的实现,如下所示:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class PeriodicTable
{
  private List<Element> elements;

  public PeriodicTable() throws IOException
  {
    elements = new ArrayList<>();
    List<String> list = Files.readAllLines(Paths.get("PeriodicTable.txt"));
    list.forEach(this::process);
  }

  public static void main(String[] args) throws IOException
  {
    final PeriodicTable periodicTable = new PeriodicTable();

    System.out.println(periodicTable.getElementByNumber(1));
    System.out.println(periodicTable.getElementBySymbol("Li"));
  }

  private void process(String line)
  {
    try (Scanner scanner = new Scanner(line))
    {
      int atomicNumber = scanner.nextInt();
      String symbol = scanner.next();
      String info = scanner.nextLine();

      elements.add(new Element(atomicNumber, symbol, info));
    }
  }

  public Element getElementByNumber(int atomicNumber)
  {
    return elements.stream().
      filter(e -> e.atomicNumber == atomicNumber).
      findFirst().orElse(null);
  }

  public Element getElementBySymbol(String symbol)
  {
    return elements.stream().
      filter(e -> e.symbol.equals(symbol)).
      findFirst().orElse(null);
  }

  private class Element
  {
    private String info;
    private int atomicNumber;
    private String symbol;

    public Element(int atomicNumber, String symbol, String info)
    {
      this.atomicNumber = atomicNumber;
      this.symbol = symbol;
      this.info = info;
    }

    public String toString()
    {
      return "[ " + atomicNumber + " " + symbol + " " + info + " ]";
    }
  }
}

如果看到的话,我创建了一个Element类,其中包含该Elementatomic numbersymbolinfo ,并且在PeriodicTable类中有一个elements列表。

我从PeriodicTable.txt文件中读取了PeriodicTable数据,并通过适当地解析文本文件并为每一行创建元素并将其添加到elements来处理文本文件的每一行。

我还添加了两种基于atomic numbersymbol属性过滤元素的方法。

该代码可在Java 8中运行,因此您至少应具有运行该代码的权限,或者可以轻松地为此代码编写将在早期JVM上运行的代码,尽管它不会像此版本那么紧凑。

由于PeriodicTable中元素的数量有限,因此,如果您的PeriodicTable.txt文件中包含原子序数增加的元素,它们将按照atomic number排序,尽管我会费心。

由于我们知道PeriodicTable中元素的确切数目及其不经常更改的内容,因此过滤方法花费的时间是恒定的。

现在,您要做的就是创建一个正确的PeriodicTable.txt文件,程序可以使用该文件。

注意: PeriodicTable类也可以用更好的方式编写。 这只是一个例子。 我可以将其作为Singleton。 我什至可以使用具有硬编码值的Element enum ,但是我认为从文件加载数据将使代码更整洁。

通过相应地更改process()方法,并根据假设更改文本文件的格式,并扩展Element类,甚至可以为每个Element增加对PeriodicTable类的附加属性,从而可以容纳更多信息。

只是为了好玩,以下是基于Singleton的解决方案:

// PeriodicTable.java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class PeriodicTable
{
  private static PeriodicTable periodicTable = new PeriodicTable();
  private List<Element> elements;

  private PeriodicTable()
  {
    try
    {
      elements = new ArrayList<>();
      List<String> list = Files.readAllLines(Paths.get("PeriodicTable.txt"));
      list.forEach(this::process);
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
  }

  public static Element getElementByNumber(int atomicNumber)
  {
    return periodicTable.elements.stream().
      filter(e -> e.atomicNumber == atomicNumber).
      findFirst().orElse(null);
  }

  public static Element getElementBySymbol(String symbol)
  {
    return periodicTable.elements.stream().
      filter(e -> e.symbol.equals(symbol)).
      findFirst().orElse(null);
  }

  private void process(String line)
  {
    try (Scanner scanner = new Scanner(line))
    {
      int atomicNumber = scanner.nextInt();
      String symbol = scanner.next();
      String info = scanner.nextLine();

      elements.add(new Element(atomicNumber, symbol, info));
    }
  }

  private class Element
  {
    private String info;
    private int atomicNumber;
    private String symbol;

    public Element(int atomicNumber, String symbol, String info)
    {
      this.atomicNumber = atomicNumber;
      this.symbol = symbol;
      this.info = info;
    }

    public String toString()
    {
      return "[ " + atomicNumber + " " + symbol + " " + info + " ]";
    }
  }
}

// Demo.java
public class Demo
{
  public static void main(String[] args)
  {
    System.out.println(PeriodicTable.getElementByNumber(1));
    System.out.println(PeriodicTable.getElementBySymbol("Li"));
  }
}

现在,您可以安全地,直接地使用您的PeriodicTable ,如Demo方法所示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM