使用带有 for 循环更改数据的 switch 语句检索

Using a switch statement with a for loop change data retrieved

我正在处理一个包含不同列数据的文件。我想用每个开关更改为每列提取的数据。我将值切换设置为我的变量,因此单击时值会发生变化。 0-2。目前我可以 运行 切换,但值不会改变。 下面是我当前的 switch 语句。有关完整代码和相关文件,请参阅 Link

     PImage mapImage;
Table locationTable;
int rowCount;
Table dataTable;
float dataMin = MAX_FLOAT;
float dataMax = MIN_FLOAT;
int toggle = 0;
int x1;
int y1;
int x2;
int y2;

void setup() {
  size(750, 600);
  smooth();
  noStroke();

  mapImage = loadImage("map.png");
  x1 = 40;
  y1 = 40;

  x2 = width - 200;
  y2 = height - 80;
  locationTable = new Table("locations.tsv");
  rowCount = locationTable.getRowCount( );
  dataTable = new Table("povertynoheader.tsv");
  switch ( toggle ) {
    case 0:
    for (int row = 0; row < rowCount; row++) {
      float value = dataTable.getFloat(row, 1);
      if (value > dataMax) {
        dataMax = value;
    }
      if (value < dataMin) {
        dataMin = value;
      }
      break;
    }
        case 1:
    for (int row = 1; row < rowCount; row++) {
      float value = dataTable.getFloat(row, 0);
      if (value > dataMax) {
        dataMax = value;
    }
      if (value < dataMin) {
        dataMin = value;
      }

    }
            case 2:
    for (int row = 1; row < rowCount; row++) {
      float value = dataTable.getFloat(row, 3);
      if (value > dataMax) {
        dataMax = value;
    }
      if (value < dataMin) {
        dataMin = value;
      }  
    }
  }
  stateData = GetStateData();
}

void draw() {
  background(255);
  image(mapImage, 0, 0);
  surface.setResizable(true);

  DrawStats();
  AddTitle();
  drawLegend();
  drawsize();
}
void AddTitle() {
  fill(0);
  textSize(20);
  textAlign(CENTER);
  if ( toggle == 0 ) {
  text("2017 Poverty Rates (%) by State", width/2, 30);
  } else if (toggle == 1) {
    text("People in poverty by Household income in thousands ", width/2, 15); 
  }  else if (toggle == 2) {
      text("2014 Poverty Rates (%) by State ", width/2, 30);
  }
}

void drawLegend(){
  fill(0);
  textSize(10);
  textAlign(CENTER);
  if ( toggle == 0 ) {
  text("2017 Poverty Rates (Lowest to Highest)", 630, 300);
   int colorWidth = 15;
   int step = 1;
    noFill();  // make sure the rectangle and the points are not filled in  
    rectMode(CORNERS);
    rect(x1,y1,x2,y2);

   // Have 5 ranges of color values 
   noStroke();
   for ( int i = 1 ; i < 10 ; i = i + 2) {

        int legendX1 = x2 + step * colorWidth;
        int legendX2 = x2 + step * colorWidth + colorWidth;
        int legendY1 = (y1 + y2) / 2 - colorWidth / 2;
        int legendY2 = (y1 + y2) / 2 + colorWidth / 2;

        step = step + 1;
        float percent = norm(i, 1,10);
        color integratedColor = lerpColor(#03fc03,#fc0303,percent);
        fill(integratedColor);        
        rect(legendX1,legendY1,legendX2,legendY2);
     }   
   }
}

void DrawStats() {
  // draw circles
  for (StateData s : stateData) {
    fill(s.fill);
    ellipseMode(RADIUS);
    ellipse(s.location.x, s.location.y, s.radius, s.radius);
  }
  // draw text above circles
  for (StateData s : stateData) {
    if (dist(s.location.x, s.location.y, mouseX, mouseY) < s.radius+2) {
      fill(0);
      textAlign(CENTER);
      textSize(10);
      text(s.povertyRate + " (" + s.name + ")", s.location.x, s.location.y-s.radius-4);
    }
  }
}

void drawsize() {


void mousePressed() {

  if (toggle == 0 ) {
     toggle = 1; 
  } else if (toggle == 1) {
     toggle = 2;
  } else {
    toggle = 0;
  }

}
void keyPressed() {
  if ( key == ' ') {
    if (toggle == 0 ) {
      toggle = 1;
  } else if (toggle == 1) {
     toggle = 2;
  } else {
    toggle = 0;
  }
  }
}

您必须在每个案例的末尾使用 break;。(如果您只想 运行 那个特定案例)。 无论 toggle 值是什么,您的代码中发生了什么; 案例 2 将始终 运行 并覆盖 case0/case1 的值。

首先我想说用户@Dakshesh Garambha 是 100% 正确的。丢失的 break 可能是你问题中最少的,所以它对你的工作影响不大,但他成功地回答了你的问题,值得感谢。您可以看到一些有关如何在我的代码中编写 switch 语句的示例。好好看看


好的,我刚打开你的工作,还有很多重构工作要做​​。但是,勇气!这一切都是非常可行的。

首先,据我了解,你想toggle在几组数据之间。没问题。您只需要相应地加载这些。您仍然必须存储它们,因此您必须修改 StateData class。因为我很懒,所以我总是尝试以正确的方式编写代码,所以我建议不要向 StateData class 添加各种细节,而是向 GetStateData() 方法添加重载,这样我们可以有几组 StateData 并即时从一组切换到另一组。

老实说,编写复杂的代码在大多数情况下都是错误的,所以让我们避免这种情况。

GetStateData 签名现在看起来像这样:

ArrayList<StateData> GetStateData(int valueColumnNumber)

此处的数字只是 povertynoheader 文件中用于获取要显示的值的列。 问题是,我们无法用 poverty2017 计算家庭数量之类的半径。全局变量 dataMindataMax 变得无用了。擦除它们。我们将分别为每个数据集计算它们。

如果到目前为止你一直在关注我,你的 StateData.pde 文件应该如下所示:

class StateData {
  public String name;
  public PVector location;
  public float value;
  public float radius;
  public color fill;

  StateData(String name, PVector location, float value, float dataMin, float dataMax) {
    this.name = name;
    this.location = location;
    this.value = value;
    this.radius = map(value, 0, dataMax, 1.5, 15);

    float colorOffset = 255 * ((value - dataMin) / (dataMax - dataMin));
    this.fill = color(colorOffset, 255-colorOffset, 0);
  }
}

// Notice how we'll just use more StateData instead of making StateData more complex:
ArrayList<StateData> poverty2017;
ArrayList<StateData> povertyHouseholds;
ArrayList<StateData> poverty2014;

ArrayList<StateData> GetStateData(int valueColumnNumber) {
  ArrayList<StateData> data = new ArrayList<StateData>();

  // Since we need to know dataMin and dataMax, we'll just calculate one pair of these per data set
  float dataMin = MAX_FLOAT;
  float dataMax = MIN_FLOAT;
  for (int row = 0; row < rowCount; row++) {
    float value = dataTable.getFloat(row, valueColumnNumber);
    if (value > dataMax) {
      dataMax = value;
    }
    if (value < dataMin) {
      dataMin = value;
    }
  }

  for (int row = 0; row < rowCount; row++) {
    String abbrev = dataTable.getRowName(row);
    float value = dataTable.getFloat(abbrev, valueColumnNumber);
    float x = locationTable.getFloat(abbrev, 1);
    float y = locationTable.getFloat(abbrev, 2);
    data.add(new StateData(abbrev, new PVector(x, y), value, dataMin, dataMax));
  }

  return data;
}

为了填充这些数组,我们将在 setup() 方法中调用 GetStateData。这里的想法是只计算所有这些东西一次,然后再计算其他东西运行,所以我们以后不用再费心了:

void setup() {
  size(750, 600);
  smooth();
  noStroke();

  mapImage = loadImage("map.png");
  x1 = 40;
  y1 = 40;
  x2 = width - 200;
  y2 = height - 80;
  locationTable = new Table("locations.tsv");
  rowCount = locationTable.getRowCount( );
  dataTable = new Table("povertynoheader.tsv");

  // notice that we're not calculating dataMin and dataMax here anymore, as we erased these globals

  poverty2017 = GetStateData(1); // column #1
  povertyHouseholds = GetStateData(2); // column #2
  poverty2014 = GetStateData(3); // column #3... I guess?
}

当然,您必须修改 DrawStats() 方法以绘制正确的数据。我建议您创建一个本地空数组列表并使用 `switch; 从正确的数据集中填充它;声明:

void DrawStats() {
  ArrayList<StateData> stateData = null;

  switch (toggle) {
    case 0:
      stateData = poverty2017;
      break;
    case 1:
      stateData = povertyHouseholds;
      break;
    case 2:
      stateData = poverty2014;
      break;
  }

  // nothing changed here: we're just drawing from a different source
  for (StateData s : stateData) {
    fill(s.fill);
    ellipseMode(RADIUS);
    ellipse(s.location.x, s.location.y, s.radius, s.radius);
  }
  // draw text (here so it's over the circles)
  for (StateData s : stateData) {
    if (dist(s.location.x, s.location.y, mouseX, mouseY) < s.radius+2) {
      fill(0);
      textAlign(CENTER);
      textSize(10);
      text(s.value + " (" + s.name + ")", s.location.x, s.location.y-s.radius-4);
    }
  }
}

给你!每次单击或按空格键时都会有不同的数据!

现在,有些挑剔:

AddTitle() 触发了我。我建议您使用与 DrawStats() 方法类似的技术重写它:

void AddTitle() {
  fill(0);
  textSize(20);
  textAlign(CENTER);

  String title = "";
  switch (toggle) {
    case 0:
      title = "2017 Poverty Rates (%) by State";
      break;
    case 1:
      title = "People in poverty by Household income in thousands";
      break;
    case 2:
      title = "2014 Poverty Rates (%) by State";
      break;
  }
  text(title, width/2, 15);
}

我改变了什么?重要的部分不是开关,而是我使用变量 title 来避免多次写入 text(title, width/2, 15);。这样,如果您更改标题的高度,就不必查找和更改代码中使用此高度的每个地方。只有一个地方需要改变。我不会 re-write drawLegend() 方法,但是当你这样做的时候,你应该记住我刚才说的;以后修复、改进或更改代码会更容易。 (如果你想知道,这叫做编写 DRY 代码——不要重复你自己。每次你复制和粘贴一行时,如果你想对它的副本之一进行更改,你必须找到它,所以每个是一个潜在的未来错误。)

同样适用于 mouseClicked() - 而不是 mousePressed(),它们不一样 - 和 keyPressed:它们基本上是复制和粘贴。相反,创建一个将代码集中在一个地方的方法:

void mouseClicked() {
  IncreaseToggle();
}

void keyPressed() {
  if ( key == ' ') { IncreaseToggle(); }
}

void IncreaseToggle() {
  toggle++;
  if (toggle>2) {toggle=0;}
}

另外:我在 povertynoheader 文件的一些数据中看到了逗号。它可能会给您带来麻烦,因为它不会轻易转换为浮点数。如果您发现缺失值,请先检查它们是否与这些行相对应。

希望这一切对您有所帮助。玩得开心!