我创建了一个字符串数组,我正在尝试将字符串数组分组。
到目前为止,我的代码看起来像这样:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[]) {
char *results[] = {"Canada", "Cycling", "Canada", "Swimming", "India", "Swimming", "New Mexico",
"Cycling", "New Mexico", "Cycling", "New Mecico", "Swimming"};
int nelements, i, country_count;
nelements = sizeof(results) / sizeof(results[0]);
for (i = 0 ; i < nelements; i++) {
printf("%s\n", results[i]);
}
return 0;
}
打印出来:
Canada
Cycling
Canada
Swimming
India
Swimming
New Mexico
Cycling
New Mexico
Cycling
New Mexico
Swimming
但是我想把各个国家的体育运动和各自的计数分组,我希望看起来像这样:
Canada
Cycling 1
Swimming 1
India
Swimming 1
New Mexico
Cycling 2
Swimming 1
我正在考虑使用数组中的每个i+2
元素对国家/地区进行分类,并使用strcmp
删除重复的国家/地区字符串,但我不知道如何使用与各个国家一起运动。
我只是不确定如何解决这个问题。任何形式的帮助将不胜感激。
答案 0 :(得分:3)
解决方案取决于您想采取何种方法。保留单个字符数组(代码中的结果*)不会使您的数据动态化。基本上,您可能希望使用存储(如果需要,嵌套)对的字典数据结构。在C中,我会使用结构来使其模块化。
首先,你需要一个结构来存储运动及其数量(比如奖牌数)
struct sport {
char *sport_name;
int medal_count;
//Any other details you want to store
};
然后,一个国家可以进行多项运动。因此,我们需要建立国家结构。
struct Country{
char *country_name;
struct sport* results;
//Any other details you want to store
};
现在让我们创建一系列国家/地区数据。
#define NO_OF_COUNTRIES 3 //You may fix this or make it dynamic
struct Country country_data[NO_OF_COUNTRIES];
您现在可以相应地填写数据。希望这会有所帮助。
答案 1 :(得分:2)
考虑使用城市和国家/地区列表而不是字符串数组。
以下代码解释了最简单的实现,其中包含两个结构和两个方法 - 添加新元素和搜索元素。
尝试使用此代码,然后了解它:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct city
{
struct city * next;
char * cityName;
int counter;
};
struct country
{
struct country * next;
char * coutryName;
struct city * cities;
};
struct country * findCountry(struct country * coutries, char * country)
{
struct country * searchResult = NULL;
while (coutries != NULL)
{
if (strcmp(country, coutries->coutryName) == 0)
{
searchResult = coutries;
break;
}
coutries = coutries->next;
}
return searchResult;
}
struct country * addCountry(struct country * coutries, char * country)
{
struct country * newCountry = malloc(sizeof(struct country));
newCountry->next = coutries;
newCountry->coutryName = country;
newCountry->cities = NULL;
return newCountry;
}
struct city * findCity(struct city * cities, char * city)
{
struct city * searchResult = NULL;
while (cities != NULL)
{
if (strcmp(city, cities->cityName) == 0)
{
searchResult = cities;
break;
}
cities = cities->next;
}
return searchResult;
}
struct city * addCity(struct city * cities, char * city)
{
struct city * newCity = malloc(sizeof(struct city));
newCity->cityName = city;
newCity->next = cities;
newCity->counter = 0;
return newCity;
}
int main(void)
{
char *results[] = { "Canada", "Cycling", "Canada", "Swimming", "India", "Swimming", "New Mexico",
"Cycling", "New Mexico", "Cycling", "New Mexico", "Swimming" };
struct country * countries = NULL;
int nelements = sizeof(results) / sizeof(results[0]);
// filling list of countries with sublists of cityes
int i;
for (i = 0; i < nelements; i+=2)
{
struct country * pCountry = findCountry(countries, results[i]);
if (!pCountry)
{
countries = addCountry(countries, results[i]);
pCountry = countries;
}
struct city * pCity = findCity(pCountry->cities, results[i+1]);
if (!pCity)
{
pCountry->cities = addCity(pCountry->cities, results[i + 1]);
pCity = pCountry->cities;
}
pCity->counter++;
}
// reading cities from all countries
struct country * pCountry = countries;
while (pCountry != NULL)
{
printf("%s\n",pCountry->coutryName);
struct city * pCity = pCountry->cities;
while (pCity != NULL)
{
printf(" %s %d\n", pCity->cityName, pCity->counter);
pCity = pCity->next;
}
printf("\n");
pCountry = pCountry->next;
}
return 0;
}
注意:在您的代码中"New Mexico"
就像"New Mecico"
一样,在我的代码中,此错误类型已修复。
<强>更新强>
注2:因为我在国家和城市的列表顺序的开头添加元素与它们在源数组中首次提及的顺序相反。
如果订单很重要,您有两种选择:
1)重写我的代码,将新项目添加到列表末尾(这是漫长的过程)
2)重写for
- 在main
中循环只是为了从最后读取初始数组(这是最简单的方法):
// filling list of countries with sublists of cityes
int i;
for (i = nelements-2; i >=0 ; i -= 2)
{
. . .
答案 2 :(得分:1)
我会使用 struct (如果您不熟悉,我总是在需要时使用myStruct.c提醒自己)并使用两个数组作为数据成员,像这样:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COUNTRY_LENGTH 15
#define MAX_SPORTS 5
enum sport_name { CYCLING, SWIMMING };
typedef struct Record {
char country[COUNTRY_LENGTH];
int sports[MAX_SPORTS];
} Record;
// return index of 'country' in 'array' if the 'country'
// is found inside 'array', else -1
int exists(char country[], Record* array, int size) {
int i;
for(i = 0; i < size; ++i)
if(!strcmp(array[i].country, country))
return i;
return -1;
}
int find_sport_index(char sport[]) {
if(!strcmp(sport, "Cycling"))
return CYCLING;
if(!strcmp(sport, "Swimming"))
return SWIMMING;
printf("I couldn't find a sport index for %s\n!!! Do something...Undefined Behavior!", sport);
return -1;
}
char* find_sport_string(int sport) {
if(sport == CYCLING)
return "Cycling";
if(sport == SWIMMING)
return "Swimming";
printf("I couldn't find a sport string for sport index %d\n!!! Do something...", sport);
return NULL;
}
int main(int argc, char *argv[]) {
// you had a typo, New Mecico, I corrected it..Also you could have used a struct here... ;)
char *results[] = {"Canada", "Cycling", "Canada", "Swimming", "India", "Swimming", "New Mexico",
"Cycling", "New Mexico", "Cycling", "New Mexico", "Swimming"};
int nelements, i, j;
nelements = sizeof(results) / sizeof(results[0]);
const int records_size = nelements/2;
Record record[records_size];
for(i = 0; i < records_size; i++) {
for(j = 0; j < COUNTRY_LENGTH; j++)
record[i].country[j] = 0;
for(j = 0; j < MAX_SPORTS; j++)
record[i].sports[j] = 0;
}
int country_index, records_count = 0;
for(i = 0; i < nelements; ++i) {
// results[i] is a country
if(i % 2 == 0) {
country_index = exists(results[i], record, records_size);
if(country_index == -1) {
country_index = records_count++;
strcpy(record[country_index].country, results[i]);
}
} else {
// result[i] is a sport
record[country_index].sports[find_sport_index(results[i])]++;
}
}
for(i = 0; i < records_size; ++i) {
if(strlen(record[i].country)) {
printf("%s\n", record[i].country);
for(j = 0; j < MAX_SPORTS; j++) {
if(record[i].sports[j] != 0) {
printf(" %s %d\n", find_sport_string(j), record[i].sports[j]);
}
}
}
}
return 0;
}
输出:
C02QT2UBFVH6-lm:~ gsamaras$ ./a.out
Canada
Cycling 1
Swimming 1
India
Swimming 1
New Mexico
Cycling 2
Swimming 1
这个想法是:
Record
保存奥运会的记录,并附有相关内容
运动。Record.country
拥有该国家的名称(我认为它
最多为14个字符,NULL终结符为+1,因此我
将定义为15)。Record.sports
是一个大小为MAX_SPORTS
的数组 - 大小为
等于奥林匹克运动会的所有运动,但我认为是5.这个阵列的每个位置都是一个计数器(每个国家参加运动的奖牌。例如,Record.sports[1] = 2
表示这个国家有2枚奖牌在游泳。但我怎么知道游泳?我决定apriori,作为一个程序员,第一个计数器连接到Cycling,第二个与游泳等等。我使用enum
使其更具可读性使用魔术数字。
(注意:您可以使用列表而不是数组,但这可能是一个
该应用程序过度杀伤。但是如果你想为了好玩而做(而且因为内存少一点),你
可以使用我们的List
(C))。results[]
,因为你应该这样做
已经使用了一个结构,但我使用了你的代码...所以我
需要一个Records
数组,其大小应该等于
国家数量,即results[]
大小的一半。
请注意,因为您将results[]
定义为包含隐式
成对的乡村运动,两个分区就足够了
确定Record
数组的大小。results[]
以填充record[]
在for-loop中命名为i
。当i
为偶数时,result[i]
包含一个国家,否则它包含一项运动。我用的是模块
运算符(%
)可以轻松确定。record[]
中不存在该国家/地区,则将其插入,否则为I
不要再插入它。在这两种情况下,我都想记住它的索引
record[]
,以便在下一次迭代中,我们将处理
运动,我们现在应该看看record[]
的位置
进入并采取相应的行动。答案 3 :(得分:1)
鉴于您的数组,我可以看到国家/地区名称可供选择。如果这是格式数据,则可以使用以下代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *results[] = {"Canada", "Cycling", "Canada", "Swimming", "India","Swimming", "New Mexico",
"Cycling", "New Mexico", "Cycling", "New Mexico", "Swimming"};
int nelements, i, sport_count=0,country_change =0;
char country[50];char sport[50];
strcpy(country,results[0]);
printf("%s\n", country);
strcpy(sport,results[1]);
nelements = sizeof(results) / sizeof(results[0]);
for (i = 1 ; i < nelements; i++)
{
if(((i%2)==0) && (strcmp(country,results[i])))
{
//sport_count++;
printf("\t%s %d\n", sport,sport_count);
country_change =1;
strcpy(country,results[i]);
printf("%s\n", country);
}
else if((i%2)==1)
{
if(country_change)
{
strcpy(sport,results[i]);
country_change = 0;
sport_count = 0;
}
if(!strcmp(sport,results[i]))
{
sport_count++;
}
else
{
printf("\t%s %d\n", sport,sport_count);
strcpy(sport,results[i]);
sport_count = 1;
}
//strcpy(country,results[i]);
}
}
printf("\t%s %d\n", sport,sport_count);
return 0;
}
基本上这就是我在这里要做的事情:
最后一项运动名称打印在循环外。
Output
Canada
Cycling 1
Swimming 1
India
Swimming 1
New Mexico
Cycling 2
Swimming 1
答案 4 :(得分:1)
这个解决方案的想法是在构建地图 - 表格中,行对应于国家/地区,列对应于体育赛事(或体育名称)。
最大可能地图的内存(大小为nelements / 2 x nelements / 2)与 angular.module('eBlood').directive('esriPointRenderersMap', ['$q', 'appConfig', 'esriLoader', 'esriRegistry', function($q, appConfig, esriLoader, esriRegistry) {
return {
// element only directive
restict: 'E',
// isolate the scope
scope: {
// 1-way string binding
rendererActive: '@',
// 2-way object binding
basemapActive: '=',
clusterTolerance: '=',
heatmapRendererParams: '='
},
compile: function($element, $attrs) {
// remove the id attribute from the main element
$element.removeAttr('id');
// append a new div inside this element, this is where we will create our map
$element.append('<div id=' + $attrs.id + '></div>');
// since we are using compile we need to return our linker function
// the 'link' function handles how our directive responds to changes in $scope
// jshint unused: false
return function(scope, element, attrs, controller) {};
},
controller: function($scope, $element, $attrs) {
var mapDeferred = $q.defer();
var esriApp = {};
// add this map to the registry
if ($attrs.registerAs) {
var deregister = esriRegistry._register($attrs.registerAs, mapDeferred.promise);
// remove this from the registry when the scope is destroyed
$scope.$on('$destroy', deregister);
}
esriApp.createGeoCordFinder = coords => {
return esriLoader.require([
'esri/geometry/Point',
'esri/tasks/Locator'
]).then(x => {
var Point = x[0];
if (!esriApp.mapLocator) {
var Locator = x[1];
esriApp.mapLocator = new Locator('https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer');
}
return esriApp.mapLocator.locationToAddress(new Point(coords)).then(res => {
return res.address.Match_addr;
});
});
};
esriApp.zoomToLocation = mapOptions => {
if (mapOptions.view) {
mapOptions.zoom = mapOptions.zoom || appConfig.pointRenderers.mapOptions.zoom;
mapOptions.view.goTo({
target: [mapOptions.coordinates.longitude, mapOptions.coordinates.latitude],
zoom: mapOptions.zoom
});
// change the marker to the current Geo.
var promise = (!mapOptions.address) ? esriApp.createGeoCordFinder(mapOptions.coordinates) : $q.when(mapOptions.address);
promise.then(location => {
esriApp.changeLocationMarker({
view: mapOptions.view,
attributes: {
address: location
},
geometry: {
longitude: mapOptions.coordinates.longitude,
latitude: mapOptions.coordinates.latitude
}
});
});
}
};
esriApp.createLocateIcon = mapOptions => {
var container;
if (!mapOptions || !mapOptions.view)
return $q.reject('Our MapView is setYet');
container = mapOptions.container |"map";
mapOptions.container = undefined;
mapOptions.goToLocationEnabled = appConfig.goToLocationEnabled;
mapOptions.graphic = null;
return esriLoader.require([
'esri/widgets/Locate'
]).then(x => {
var Locate = x[0];
esriApp.locateWidget = new Locate(mapOptions, container);
esriApp.locateWidget.startup();
if (!container)
mapOptions.view.ui.add(esriApp.locateWidget, 'top-left');
esriApp.locateWidget.on('locate', data => {
esriApp.zoomToLocation({
view: mapOptions.view,
coordinates: data.position.coords
});
});
return esriApp.locateWidget;
});
};
function setSearchWidget(opts) {
var srcNodeRef;
if (!opts || !opts.view) {
return $q.reject('MapView is undefined');
}
srcNodeRef = opts.container;
opts.container = undefined;
opts.showPopupOnSelect = false;
opts.autoSelect = false;
return esriLoader.require([
'esri/widgets/Search'
]).then(x => {
var Search = x[0];
var searchWidget = new Search(opts, srcNodeRef);
searchWidget.startup();
if (!srcNodeRef) {
opts.view.ui.add(searchWidget, 'top-right');
}
searchWidget.on('search-complete', e => {
if (e.results.length > 0 && e.results[0].results.length > 0) {
var res = e.results[0].results[0];
var coords = {
longitude: res.feature.geometry.longitude,
latitude: res.feature.geometry.latitude
};
esriApp.zoomToLocation({
view: opts.view,
coordinates: coords,
address: res.name
});
}
});
return searchWidget;
});
}
var mapoption = {
map: esriApp.map,
container: 'map',
zoom: 3,
padding: {
top: 65
},
view: esriApp.mapView
};
esriApp.buildmap = (mapViewDiv) => {
return esriApp.creatMap({
basemap: $scope.basemapActive
})
.then(map => {
mapoption.map = map;
mapoption.container = mapViewDiv;
return esriApp.createMapView(mapoption);
});
};
esriApp.creatMap = properties => {
return esriLoader.require(['esri/Map'])
.then(esriModules => {
var Map = esriModules[0];
return new Map(properties);
});
};
esriApp.createMapView = config => {
return esriLoader.require(['esri/views/MapView'])
.then(x => {
var MapView = x[0];
esriApp.mapView = new MapView(config);
mapDeferred.resolve({
view: esriApp.mapView
});
return mapDeferred.promise;
});
};
esriApp.map = esriApp.buildmap($attrs.id);
mapoption.view = esriApp.mapView;
esriApp.createLocateIcon(mapoption);
setSearchWidget(mapoption);
mapDeferred.promise.then(function(esriApp) {
// clean up
$scope.$on('$destroy', function() {
esriApp.map.destroy();
});
});
// });
}
};
}]);
一起分配,但如果calloc
未更改,实际上只有int[6][6]
。
char *results[]
因此,当#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *results[] = { "Canada", "Cycling", "Canada", "Swimming", "India", "Swimming", "New Mexico",
"Cycling", "New Mexico", "Cycling", "New Mexico", "Swimming" };
int nelements = sizeof(results) / sizeof(results[0]);
int i;
// making empty map
int ** map = calloc(nelements/2, sizeof(int*));
for (i = 0; i < nelements / 2; i++)
map[i] = calloc(nelements/2, sizeof(int));
char ** rowNames = calloc(nelements / 2, sizeof(char*));
int usedRows = 0;
char ** colNames = calloc(nelements / 2, sizeof(char*));
int usedCols = 0;
// filling the map
// the outer loop for countries
int c;
for (c = 0; c < nelements; c+=2) {
int row = -1;
// Find country in the map (loop for rows)
for (i = 0; i < usedRows; i++)
{
if (strcmp(results[c], rowNames[i]) == 0)
{
row = i;
break;
}
}
// or add if it is new country
if (row < 0)
{
row = usedRows;
rowNames[usedRows] = results[c];
usedRows++;
}
// Find sport in the map (loop for columns)
int col = -1;
for (i = 0; i < usedCols; i++)
{
if (strcmp(results[c+1], colNames[i]) == 0)
{
col = i;
break;
}
}
// or add if it is new sport
if (col < 0)
{
col = usedCols;
colNames[usedCols] = results[c+1];
usedCols++;
}
// Just count sport event in the current country
map[row][col]++;
}
// print results from map
// the outer loop for countries (loop for rows in map)
for (c = 0; c < usedRows; c++) {
printf("%s\n", rowNames[c]);
// the inner loop for sport
for (i = 0; i < usedCols; i++)
if (map[c][i])
printf(" %s %d\n", colNames[i], map[c][i]);
printf("\n");
}
return 0;
}
,map
(与国家/地区)和rowNames
(与体育)相关时,我们可以以任何方式输出数据。
答案 5 :(得分:1)
从答案数量可以看出,有很多方法可以解决这个问题。对于国家/地区或事件(但不是两者),您将需要的一个元素是包含国家/地区条目或事件条目的简单查找表,以便您区分results
中的值是国家/地区名称还是事件名称。一个简单的国家/地区查询(在这里制作全局,但也可以是函数范围),例如以下作品:
char *countries[] = { "Canada", "India", "New Mexico" }; /* countries lookup */
你可以采取的另一个捷径是识别结果中的指针具有定义的函数作用域,因此不需要复制或分配内存来保存它们 - 它们已经存在于只读内存中。
另一个有用的结构元素是保持与国家/地区相关联的事件的计数,例如eventcnt
。每次在国家/地区下添加事件时,都可以增加。您可以使用类似于:
typedef struct {
char *country;
char *event[MAXE];
int eventcnt;
} host;
(MAXE
是所涉及的最大事件的简单常量,允许您对结构数组使用自动存储。(可以根据需要轻松更改以分配/重新分配存储)< / p>
然后,您需要简单地遍历results
数组,一次,了解事件始终跟在他们之前的国家/地区。使用多个嵌套循环可以将results
遍历的次数保持为一次。基本上,你循环遍历results
中的每个指针,确定它是否指向国家/地区名称,如果它是国家/地区名称,那么如果它不存在,则添加它作为host.country
值之一,如果确实跳过它(不需要更新指针指向最后一次出现的国家名称)
由于涉及嵌套循环,因此简单的goto
提供了确定何时处理country
名称时所需的所有控件,以及处理event
名称时允许的采取每种情况下所需的行动。
然后,只需打印/使用您想要的结果,现在包含在带有hidx
(主机索引)的struct数组中,其中包含所涉及的唯一主机总数。
将各个部分放在一起,你可以做类似以下的事情:
#include <stdio.h>
#include <string.h>
/* constants max(countries, events) */
enum { MAXC = 8, MAXE = 16 };
char *countries[] = { "Canada", "India", "New Mexico" }; /* countries lookup */
typedef struct {
char *country;
char *event[MAXE];
int eventcnt;
} host;
int main (void) {
char *results[] = { "Canada", "Cycling", "Canada", "Swimming",
"India", "Swimming", "New Mexico", "Cycling",
"New Mexico", "Cycling", "New Mexico", "Swimming"};
host hosts[MAXC] = {{ .country = NULL }};
int hidx = 0, i, j, country_count, current = 0, nelements;
country_count = sizeof countries/sizeof *countries;
nelements = sizeof results / sizeof *results;
for (i = 0 ; i < nelements; i++) { /* for each element */
for (j = 0; j < country_count; j++) { /* check if country */
if (strcmp (results[i], countries[j]) == 0) { /* if so */
int k;
for (k = 0; k < hidx && /* check if already assigned */
strcmp (hosts[k].country, countries[j]); k++) {}
if (!hosts[k].country) { /* if not, assign ptr, increment */
hosts[hidx++].country = results[i];
current = hidx - 1;;
}
goto nextc; /* skip event adding */
}
} /* results[i] is not a country, check if event exists for host */
if (hosts[current].eventcnt < MAXE) { /* if it doesn't, add it */
int k;
for (k = 0; k < hosts[current].eventcnt; k++)
if (strcmp (results[i], hosts[current].event[k]) == 0)
goto nextc; /* already exists for host, skip add */
hosts[current].event[hosts[current].eventcnt++] = results[i];
}
nextc:;
}
for (i = 0; i < hidx; i++) { /* output countries & events for each */
printf (" %s\n", hosts[i].country);
for (j = 0; j < hosts[i].eventcnt; j++)
printf (" %s\n", hosts[i].event[j]);
}
return 0;
}
示例使用/输出
$ ./bin/events
Canada
Cycling
Swimming
India
Swimming
New Mexico
Cycling
Swimming
查看所有答案。包含许多好处。如果您有任何问题,请告诉我。
答案 6 :(得分:1)
我会枚举体育和地点,将NUM_ x 添加为最后一个元素,以便将来可以轻松添加枚举...
typedef enum _sport_t
{
CYCLING,
SWIMMING,
NUM_SPORTS
} sport_t;
typedef enum _location_t
{
CANADA,
INDIA,
NEW_MEXICO,
NUM_LOCATIONS
} location_t;
现在,您可以定义要在打印名称时使用的字符串数组...
char* sports_name[NUM_SPORTS] = {"Cycling", "Swimming"};
char* location_name[NUM_LOCATIONS] = {"Canada", "India", "New Mexico"};
这种方法会减少存储空间并提高效率,因为在对列表进行分类时,您将比较枚举(整数)而不是字符串。
您可能还想考虑使用所有位置和所有运动的二维布尔数组,指示所述位置是否具有所述运动。
typedef enum _bool_t
{
FALSE,
TRUE
} bool_t;
bool_t sports_array[NUM_LOCATIONS][NUM_SPORTS] =
{
{TRUE,TRUE}, // Canada
{TRUE,FALSE}, // India
{TRUE,TRUE}, // New Mexico
};
所以,你的循环看起来像这样......
location_t l;
sport_t s;
for (l = (location_t)0; l < NUM_LOCATIONS; l++)
{
printf( " %s\n", location_name[l] );
for (s = (sport_t)0; s < NUM_SPORTS; s++)
{
if (sports_array[l,s])
{
printf( " %s\n", sport_name[s] );
}
}
}