如何通过自定义功能对列表进行排序,并丢弃重复项?

lge*_*get 5 sorting r

我有这个清单:

thresholds <- list(
     list(color="red", value=100),
     list(color="blue", value=50),
     list(color="orange", value=100),
     list(color="green", value=1),
     list(color="orange", value=50)
)
Run Code Online (Sandbox Code Playgroud)

我想按每个元素的“值”字段对其进行排序,并丢弃重复项,以使结果列表中没有两个元素具有相同的“值”字段(当出现平局时被选择的元素无关紧要)。

sort并且unique不能使用复杂的列表,也不允许自定义排序。如何达到预期的效果?

lge*_*get 7

首先,在这种特殊情况下,要排序的实际向量为:

values <- sapply(thresholds, function (t) t$value)
# values == c(100, 50, 100, 1, 50)
Run Code Online (Sandbox Code Playgroud)

您可以根据sapply需要调整内部函数(例如,根据要按数字顺序还是字母顺序进行排序等)。

从这一点出发,如果我们要保留重复项,答案将是:

thresholds[order(values)]
Run Code Online (Sandbox Code Playgroud)

order对于“值”中的每个元素,返回其排名,即,如果对向量进行了排序,则返回其位置。这order(values)4 2 5 1 3。然后,thresholds[order(values)]返回thresholds由这些索引标识的元素,产生1 50 50 100 100

但是,由于我们要删除重复项,因此不能这么简单。unique将无法使用thresholds,如果将其应用于values,它将丢失与原始列表中索引的对应关系。

解决方案是使用另一个功能,即duplicated。当应用于向量时,duplicated返回一个布尔向量,指示每个元素是否早已在向量中存在。例如,duplicated(values)将返回FALSE FALSE TRUE FALSE TRUE。这个向量是我们这里需要的重复元素的过滤器。

因此,解决方案是:

ordering <- order(values)
nodups <- ordering[!duplicated(values)]
thresholds[nodups]
Run Code Online (Sandbox Code Playgroud)

或单线:

thresholds[order(values)[!duplicated(values)]]
Run Code Online (Sandbox Code Playgroud)


ale*_*laz 2

为了完整起见,关于问题的“自定义排序”/“自定义唯一”部分添加另一个替代方案。通过定义某些函数的方法(如 中所示?xtfrm),我们可以将自定义sort函数unique应用于任何列表(或其他对象)。

首先,需要添加一个“class”属性:

class(thresholds) = "thresholds"
Run Code Online (Sandbox Code Playgroud)

然后,定义必要的自定义函数:

"==.thresholds" = function(x, y) return(x[[1]][["value"]] == y[[1]][["value"]])
">.thresholds" = function(x, y) return(x[[1]][["value"]] > y[[1]][["value"]])
"[.thresholds" = function(x, i) return(structure(.subset(x, i), class = class(x)))
is.na.thresholds = function(x) return(is.na(x[[1]][["value"]]))
Run Code Online (Sandbox Code Playgroud)

现在,我们可以申请sort

sort(thresholds)
Run Code Online (Sandbox Code Playgroud)

最后添加一个自定义unique函数:

duplicated.thresholds = function(x, ...) return(duplicated(sapply(x, function(elt) elt[["value"]])))
unique.thresholds = function(x, ...) return(x[!duplicated((x))])
Run Code Online (Sandbox Code Playgroud)

和:

sort(unique(thresholds))
Run Code Online (Sandbox Code Playgroud)

(类似的答案和更多信息在这里这里