Ошибка означает, что значение CategoryList
равно нулю (и в результате метод DropDownListFor()
ожидает, что первый параметр имеет тип IEnumerable
).
Вы не генерируете вход для каждого свойства каждого SelectListItem
в CategoryList
(и не должен), поэтому никакие значения для SelectList
не отправляются в метод контроллера, и поэтому значение model.CategoryList
в методе POST равно null
, Если вы вернете представление, вы должны сначала переназначить значение CategoryList
, как и в методе GET.
public ActionResult Create(ProjectVM model)
{
if (!ModelState.IsValid)
{
model.CategoryList = new SelectList(db.Categories, "ID", "Name"); // add this
return View(model);
}
// Save and redirect
}
Чтобы объяснить внутреннюю работу (исходный код может быть см. здесь )
Каждая перегрузка DropDownList()
и DropDownListFor()
в конечном итоге вызывает следующий метод
private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata,
string optionLabel, string name, IEnumerable selectList, bool allowMultiple,
IDictionary htmlAttributes)
, который проверяет, есть ли selectList
(второй параметр из @Html.DropDownListFor()
) является null
// If we got a null selectList, try to use ViewData to get the list of items.
if (selectList == null)
{
selectList = htmlHelper.GetSelectData(name);
usedViewData = true;
}
, который, в свою очередь, вызывает
private static IEnumerable GetSelectData(this HtmlHelper htmlHelper, string name)
, который оценивает первый параметр @Html.DropDownListFor()
(в данном случае CategoryID
)
....
o = htmlHelper.ViewData.Eval(name);
....
IEnumerable selectList = o as IEnumerable;
if (selectList == null)
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
MvcResources.HtmlHelper_WrongSelectDataType,
name, o.GetType().FullName, "IEnumerable"));
}
Поскольку свойство CategoryID
является typeof int
, оно не может быть передано в IEnumerable
, и генерируется исключение (которое определено в файле MvcResources.resx
как)
The ViewData item that has the key '{0}' is of type '{1}' but must be of type '{2}'.
Перекодирование может означать много вещей и существенно сложно.
Изменение уровней фактора может быть выполнено с помощью функции levels
:
> #change the levels of a factor
> levels(veteran$celltype) <- c("s","sc","a","l")
Преобразование непрерывная переменная просто включает в себя применение векторизованной функции:
mtcars $ mpg.log & lt; - log (mtcars $ mpg)
blockquote>Для непрерывной непрерывной работы данные смотрят на
cut
иcut2
(в пакете hmisc). Например:> #make 4 groups with equal sample sizes > mtcars[['mpg.tr']] <- cut2(mtcars[['mpg']], g=4) > #make 4 groups with equal bin width > mtcars[['mpg.tr2']] <- cut(mtcars[['mpg']],4, include.lowest=TRUE)
Для перекодировки непрерывных или фактор-переменных в категориальную переменную есть
recode
в автомобильной упаковке иrecode.variables
в пакете Deducer> mtcars[c("mpg.tr2")] <- recode.variables(mtcars[c("mpg")] , "Lo:14 -> 'low';14:24 -> 'mid';else -> 'high';")
Если вы ищете графический интерфейс, Deducer реализует перекодировку с диалоговыми окнами Transform и Recode:
http://www.deducer.org/pmwiki/pmwiki.php?n=Main.TransformVariables
http://www.deducer.org/pmwiki/pmwiki.php?n=Main.RecodeVariables
Я обнаружил, что иногда бывает проще конвертировать не числовые коэффициенты в символ, прежде чем пытаться их изменить.
df <- data.frame(example=letters[1:26])
example <- as.character(df$example)
example[example %in% letters[1:20]] <- "a"
example[example %in% letters[21:26]] <- "b"
Кроме того, при импорте данных может быть полезно убедиться, что числа фактически являются числовыми перед попыткой конвертировать:
df <- data.frame(example=1:100)
example <- as.numeric(df$example)
example[example < 20] <- 1
example[example >= 20 & example < 80] <- 2
example[example >= 80] <- 3
Если вы хотите перекодировать уровни фактора, forcats
может пригодиться. Вы можете прочитать главу R для Data Science для обширного учебника, но вот суть этого.
library(tidyverse)
library(forcats)
gss_cat %>%
mutate(partyid = fct_recode(partyid,
"Republican, strong" = "Strong republican",
"Republican, weak" = "Not str republican",
"Independent, near rep" = "Ind,near rep",
"Independent, near dem" = "Ind,near dem",
"Democrat, weak" = "Not str democrat",
"Democrat, strong" = "Strong democrat",
"Other" = "No answer",
"Other" = "Don't know",
"Other" = "Other party"
)) %>%
count(partyid)
#> # A tibble: 8 × 2
#> partyid n
#> <fctr> <int>
#> 1 Other 548
#> 2 Republican, strong 2314
#> 3 Republican, weak 3032
#> 4 Independent, near rep 1791
#> 5 Independent 4119
#> 6 Independent, near dem 2499
#> # ... with 2 more rows
Вы даже можете позволить R решить, какие категории (фактор уровни) для объединения.
Иногда вам просто нужно собрать все небольшие группы, чтобы упростить график или таблицу. Это работа fct_lump (). [...] Поведение по умолчанию состоит в том, чтобы постепенно группировать наименьшие группы, гарантируя, что агрегат все еще является самой маленькой группой.
blockquote>gss_cat %>% mutate(relig = fct_lump(relig, n = 10)) %>% count(relig, sort = TRUE) %>% print(n = Inf) #> # A tibble: 2 × 2 #> relig n #> <fctr> <int> #> 1 Protestant 10846 #> 2 Other 10637
Я нахожу это очень удобным, когда несколько значений должны быть преобразованы (как это делает код в Stata):
# load package and gen some data
require(car)
x <- 1:10
# do the recoding
x
## [1] 1 2 3 4 5 6 7 8 9 10
recode(x,"10=1; 9=2; 1:4=-99")
## [1] -99 -99 -99 -99 5 6 7 8 2 1
Я нашел mapvalues
из пакета plyr
очень удобно. Пакет также содержит функцию revalue
, которая похожа на car:::recode
.
Следующий пример будет «перекодировать»
> mapvalues(letters, from = c("r", "o", "m", "a", "n"), to = c("R", "O", "M", "A", "N"))
[1] "A" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "M" "N" "O" "p" "q" "R" "s" "t" "u" "v" "w" "x" "y" "z"
recode
в пакетеcar
. Его также можно использовать для сопоставления одного набора категорий с другим набором (например, когда вы хотите свернуть кучу небольших категорий в категорию «другие»). – Jeromy Anglim 21 March 2011 в 05:59dput(levels(var))
, затем вставляю и редактирую вывод, прежде чем давать емуlevels(var)<-
. Я считаю это довольно удобным. – juba 21 March 2011 в 09:53