2017-07-16 1 views
1

J'ai une liste de vecteurs Je veux trouver tous les vecteurs communs. C'est-à-dire, ceux qui contiennent exactement les mêmes éléments, en gardant le numéro de position de chaque liste dans R. Une commande de doublure si possible.Trouver toute la liste des correspondances dans les listes de listes

Voici mylist:

mylist<-list(c("yes", "no"), c("no", "other", "up", 
"down"), c("no", "yes"), c("no", 
"yes"), c("no", "yes", "maybe"), c("no", 
"yes", "maybe"), c("no", "yes", "maybe")) 

sortie souhaitée:

Listes communes sont: Match 1: 1,3,4 Match 2: 5,6,7

+1

J'espère que je l'ai fixé @lmo –

+0

Une alternative simple est 'ML2 = lapply (mylist, tri); match (ml2, unique (ml2)) ' –

+0

@alexis_laz votre solution ne fournit pas la position des listes correspondantes pour chaque match! Vérifiez la réponse d'Akrun. Merci quand même pour votre temps! –

Répondre

4

Voici une option à l'aide split

Filter(function(x) length(x) >1, split(seq_along(mylist), 
        sapply(mylist, function(x) toString(sort(x))))) 
#$`maybe, no, yes` 
#[1] 5 6 7 

#$`no, yes` 
#[1] 1 3 4 
+1

Cela fonctionne comme un charme! Merci à tous! –

+0

Pouvez-vous écrire des commentaires, comment cela fonctionne exactement? merci Akron! –

+2

@EliasEstatisticsEU L'idée est de «scinder» la séquence de «mylist» par un groupe de «vector» créé en collant les éléments 'sort'ed du 'mylist' puis de« Filter' la 'list' de séquence ayant une longueur c'est-à-dire supérieur à 1. – akrun

4

duplicated accepte les listes comme son argument principal. Vous pouvez donc utiliser

which(duplicated(mylist1) | duplicated(mylist1, fromLast=TRUE)) 
[1] 3 4 5 6 7 

pour votre premier exemple. Notez que ceci ne fera pas la distinction entre les groupes d'éléments de liste avec des éléments communs, mais retournera TRUE uniquement pour les éléments avec des éléments identiques.

Pour le second exemple ensemble de données, vous pouvez utiliser les éléments suivants pour trouver les positions des groupes

# get group values as integers 
groups <- as.integer(factor(sapply(mylist2, 
            function(x) paste(sort(x), collapse="")))) 
# return list of groups 
lapply(seq_len(max(groups)), function(x) which(x == groups)) 
[[1]] 
[1] 2 

[[2]] 
[1] 5 6 7 

[[3]] 
[1] 1 3 4 

données

mylist1 <- 
list(c("yes", "no"), c("no", "other", "up", "down"), c("no", 
"yes", "maybe"), c("no", "yes", "maybe"), c("no", "yes", "maybe" 
), c("no", "yes", "maybe"), c("no", "yes", "maybe")) 

mylist2 <- 
list(c("yes", "no"), c("no", "other", "up", "down"), c("no", 
"yes"), c("no", "yes"), c("no", "yes", "maybe"), c("no", "yes", 
"maybe"), c("no", "yes", "maybe")) 
+0

mis à jour ma question –

+0

Je veux faire la distinction entre les matchs, voir la question mise à jour. merci –

+5

@EliasEstatisticsEU S'il vous plaît éviter de poster des questions de cibles mobiles. Il peut être très frustrant de passer du temps sur une réponse qui devient soudainement invalide après une modification (et peut-être même injustement downvoted, comme ici). S'il vous plaît, prenez le temps de bien réfléchir à votre problème avant de poster. À votre santé. – Henrik

1

Cela fonctionne pour moi:

mylist<-list(c("yes", "no"), c("no", "other", "up", 
           "down"), c("no", "yes"), c("no", 
                  "yes"), c("no", "yes", "maybe"), c("no", 
                          "yes", "maybe"), c("no", "yes", "maybe")) 

library(dplyr) 

# function to create a dataframe from your list. Might not be the most efficient way to do this. 
f <- function(data) { 
    nCol <- max(vapply(data, length, 0)) 
    data <- lapply(data, function(row) c(row, rep(NA, nCol-length(row)))) 
    data <- matrix(unlist(data), nrow=length(data), ncol=nCol, byrow=TRUE) 
    data.frame(data) 
} 

# create a dataframe from the list, and add a 'key' column 
df = f(mylist) 
df$key = apply(df , 1 , paste , collapse = "-") 

# find the total times the key occurs 
df_total = df %>% group_by(key) %>% summarise(n =n()) 

# find the indices that belong to the groups 
result = lapply(df_total$key, function(x) which(df$key==x)) 

Résultat:

> result 
[[1]] 
[1] 2 

[[2]] 
[1] 5 6 7 

[[3]] 
[1] 3 4 

[[4]] 
[1] 1 

Espérons que cela aide!

+0

Même si cela fonctionne, je ne peux pas l'accepter comme une réponse acceptée parce que ce n'est pas un seul. Merci pour votre réponse F Maas –

+1

Pourquoi une doublure est-elle nécessaire? – Florian

+0

Parce que je veux garder mon code propre! –

1

données

mylist <- list(c("yes", "no"), c("no", "other", "up", "down"), c("no", "yes"), 
      c("no", "yes"), c("no", "yes", "maybe"), c("no", "yes", "maybe"), 
      c("no", "yes", "maybe")) 

un (long) one-liner

sapply(unique(unlist(lapply(mylist, function(x) paste(sort(x), collapse = " ")))), function(y) which(y == unlist(lapply(mylist, function(x) paste(sort(x), collapse = " "))))) 

sortie:

$`no yes` 
[1] 1 3 4 

$`down no other up` 
[1] 2 

$`maybe no yes` 
[1] 5 6 7 
+0

Bravo que tu l'aies fait! (geek grec?) –

+1

oui elias je suis grec (y), j'espère que le oneliner vous aidera. – lampros

2

En voici une pour s'amuser. Vous pouvez utiliser mtabulate du package qdapTools pour obtenir la trame de données suivante,

d1 <- qdapTools::mtabulate(mylist) 
d1 
# down maybe no other up yes 
#1 0  0 1  0 0 1 
#2 1  0 1  1 1 0 
#3 0  0 1  0 0 1 
#4 0  0 1  0 0 1 
#5 0  1 1  0 0 1 
#6 0  1 1  0 0 1 
#7 0  1 1  0 0 1 

Et vous pouvez le diviser en collant,

l1 <- split(d1, do.call(paste, d1)) 

l1 
#$`0 0 1 0 0 1` 
# down maybe no other up yes 
#1 0  0 1  0 0 1 
#3 0  0 1  0 0 1 
#4 0  0 1  0 0 1 

#$`0 1 1 0 0 1` 
# down maybe no other up yes 
#5 0  1 1  0 0 1 
#6 0  1 1  0 0 1 
#7 0  1 1  0 0 1 

#$`1 0 1 1 1 0` 
# down maybe no other up yes 
#2 1  0 1  1 1 0 

Vous pouvez utiliser cette liste comme vous le voulez, à savoir

Ou encore,

setNames(lapply(l1, rownames), lapply(l1, function(i)toString(names(i)[i[1,] == 1]))) 
#$`no, yes` 
#[1] "1" "3" "4" 

#$`maybe, no, yes` 
#[1] "5" "6" "7" 

#$`down, no, other, up` 
#[1] "2" 
+0

Après avoir créé "d1" (qui, soit dit en passant, peut être simplement créé comme 'd1 = table (rep (1: longueur (mylist), longueurs (mylist)), unlist (mylist))'), pour éviter les coercions et 'paste'ing, les groupes peuvent être créés avec' d1% *% (2^(0: (ncol (d1) - 1))) 'diviser par –

+0

@alexis_laz merci pour les suggestions. Je ne comprends pas comment ce code de regroupement fonctionne (ou ne fait pas - jette une erreur) ... mais je veux dire la logique derrière cela – Sotos

+0

Il convertit fondamentalement chaque ligne en un entier suivant une sorte d'approche binaire -> décimal. C'est une alternative fantaisiste de 'apply (d1, 1, fonction (x) somme (x * (2^(0: (longueur (x) - 1))))); il est affiché de temps en temps ici sur SO. –