使用带有 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 计算家庭数量之类的半径。全局变量 dataMin
和 dataMax
变得无用了。擦除它们。我们将分别为每个数据集计算它们。
如果到目前为止你一直在关注我,你的 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
文件的一些数据中看到了逗号。它可能会给您带来麻烦,因为它不会轻易转换为浮点数。如果您发现缺失值,请先检查它们是否与这些行相对应。
希望这一切对您有所帮助。玩得开心!
我正在处理一个包含不同列数据的文件。我想用每个开关更改为每列提取的数据。我将值切换设置为我的变量,因此单击时值会发生变化。 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 计算家庭数量之类的半径。全局变量 dataMin
和 dataMax
变得无用了。擦除它们。我们将分别为每个数据集计算它们。
如果到目前为止你一直在关注我,你的 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
文件的一些数据中看到了逗号。它可能会给您带来麻烦,因为它不会轻易转换为浮点数。如果您发现缺失值,请先检查它们是否与这些行相对应。
希望这一切对您有所帮助。玩得开心!