4

I am building a project that tells me the unique words in a piece of text.

I have my orginal string scriptTextView which I have added each word into the array scriptEachWordInArray

I would now like to create an array called scriptUniqueWords which only includes words that appear once (in other words are unique) in scriptEachWordInArray

So I'd like my scriptUniqueWords array to equal = ["Silent","Holy"] as a result.

I don't want to create an array without duplicates but an array that has only values that appeared once in the first place.

var scriptTextView = "Silent Night Holy Night"
var scriptEachWordInArray = ["Silent", "night", "Holy", "night"]
var scriptUniqueWords = [String]()
for i in 0..<scriptEachWordInArray.count {
 if scriptTextView.components(separatedBy: "\(scriptEachWordInArray[i]) ").count == 1 {
 scriptUniqueWords.append(scriptEachWordInArray[i])
 print("Unique word \(scriptEachWordInArray[i])")}
}
asked Dec 21, 2016 at 21:54
5
  • 2
    Tried a Set ? Commented Dec 21, 2016 at 21:55
  • 2
    stackoverflow.com/a/29904817/456791, stackoverflow.com/questions/27624331/… Commented Dec 21, 2016 at 21:58
  • 1
    @jtbandes @Bek Thanks, but doesn't the Set technique remove all duplicates so each word will appear once instead of a possible multiple times. Night will appear in the array just once instead of twice. Whereas I am hoping to isolate just the unique values. I've tried this, or am I missing something. Commented Dec 21, 2016 at 22:02
  • Reopening because I'm convinced this question is different from the others linked. However, I still think you could use Sets to solve the problem. Commented Dec 21, 2016 at 22:03
  • @jtbandes Sure, un-dupe-hammering is perfectly reasonable if you think I was wrong. Commented Dec 21, 2016 at 22:29

4 Answers 4

7

You can use NSCountedSet

let text = "Silent Night Holy Night"
let words = text.lowercased().components(separatedBy: " ")
let countedSet = NSCountedSet(array: words)
let singleOccurrencies = countedSet.filter { countedSet.count(for: 0ドル) == 1 }.flatMap { 0ドル as? String }

Now singleOccurrencies contains ["holy", "silent"]

answered Dec 21, 2016 at 22:02

Comments

7

Swift

lets try It.

let array = ["1", "1", "2", "2", "3", "3"]
let unique = Array(Set(array))
// ["1", "2", "3"]
answered May 3, 2017 at 6:49

Comments

2

Filtering out unique words without preserving order

As another alternative to NSCountedSet, you could use a dictionary to count the the number of occurrences of each word, and filter out those that only occur once:

let scriptEachWordInArray = ["Silent", "night", "Holy", "night"]
var freqs: [String: Int] = [:]
scriptEachWordInArray.forEach { freqs[0ドル] = (freqs[0ドル] ?? 0) + 1 }
let scriptUniqueWords = freqs.flatMap { 0ドル.1 == 1 ? 0ドル.0 : nil }
print(scriptUniqueWords) // ["Holy", "Silent"]

This solution, however (as well as the one using NSCountedSet), will not preserve the order of the original array, since a dictionary as well as NSCountedSet is an unordered collection.


Filtering out unique words while preserving order

If you'd like to preserve the order from the original array (removing element which appear more than once), you could count the frequencies of each word, but store it in a (String, Int) tuple array rather than a dictionary.

Making use of the Collection extension from this Q&A

extension Collection where Iterator.Element: Hashable {
 var frequencies: [(Iterator.Element, Int)] {
 var seen: [Iterator.Element: Int] = [:]
 var frequencies: [(Iterator.Element, Int)] = []
 forEach {
 if let idx = seen[0ドル] {
 frequencies[idx].1 += 1
 }
 else {
 seen[0ドル] = frequencies.count
 frequencies.append((0,ドル 1))
 }
 }
 return frequencies
 }
}
// or, briefer but worse at showing intent
extension Collection where Iterator.Element: Hashable {
 var frequencies: [(Iterator.Element, Int)] {
 var seen: [Iterator.Element: Int] = [:]
 var frequencies: [(Iterator.Element, Int)] = []
 for elem in self {
 seen[elem].map { frequencies[0ドル].1 += 1 } ?? {
 seen[elem] = frequencies.count
 return frequencies.append((elem, 1))
 }()
 }
 return frequencies
 }
}

... you may filter out the unique words of your array (while preserving order) as

let scriptUniqueWords = scriptEachWordInArray.frequencies
 .flatMap { 0ドル.1 == 1 ? 0ドル.0 : nil }
print(scriptUniqueWords) // ["Silent", "Holy"]
answered Dec 21, 2016 at 22:11

3 Comments

Use NSCountedSet for this.
@Alexander NSCountedSet is one good Foundation approach; diversity, imho, is interesting for SO answers (hence the "as another alternative" for the dictionary approach above). Also useful to include a method for when we'd like to preserve the order from the original array.
@dfri you might be interested in this one stackoverflow.com/a/46376175/2303865
-1

you can filter the values that are already contained in the array:

let newArray = array.filter { !array.contains(0ドル) }
HDJEMAI
9,83048 gold badges77 silver badges99 bronze badges
answered May 2, 2017 at 0:54

1 Comment

This would not work, because array already contains all its own elements. Hence the expression !array.contains(0ドル) always return false.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.